Commit b5009ce5 authored by Mark Florisson's avatar Mark Florisson

Compare memoryview type pointers directly when coercing from memoryview to memoryview slice

parent 721f6ecd
...@@ -784,11 +784,14 @@ impl = """ ...@@ -784,11 +784,14 @@ impl = """
""") """)
raise_buffer_fallback_code = load_buffer_utility("BufferFallbackError") raise_buffer_fallback_code = load_buffer_utility("BufferFallbackError")
buffer_structs_code = load_buffer_utility("BufferFormatStructs") buffer_structs_code = load_buffer_utility(
"BufferFormatStructs", proto_block='utility_code_proto_before_types')
acquire_utility_code = load_buffer_utility("BufferFormatCheck", acquire_utility_code = load_buffer_utility("BufferFormatCheck",
context=context, context=context,
requires=[buffer_structs_code]) requires=[buffer_structs_code])
# See utility code BufferFormatFromTypeInfo # See utility code BufferFormatFromTypeInfo
_typeinfo_to_format_code = load_buffer_utility( _typeinfo_to_format_code = load_buffer_utility("TypeInfoToFormat", context={},
"TypeInfoToFormat", context={}, requires=[buffer_structs_code]) requires=[buffer_structs_code])
typeinfo_compare_code = load_buffer_utility("TypeInfoCompare", context={},
requires=[buffer_structs_code])
\ No newline at end of file
...@@ -897,7 +897,8 @@ memviewslice_init_code = load_memview_c_utility( ...@@ -897,7 +897,8 @@ memviewslice_init_code = load_memview_c_utility(
context=dict(context, BUF_MAX_NDIMS=Options.buffer_max_dims), context=dict(context, BUF_MAX_NDIMS=Options.buffer_max_dims),
requires=[memviewslice_declare_code, requires=[memviewslice_declare_code,
Buffer.acquire_utility_code, Buffer.acquire_utility_code,
atomic_utility], atomic_utility,
Buffer.typeinfo_compare_code],
) )
memviewslice_index_helpers = load_memview_c_utility("MemviewSliceIndex") memviewslice_index_helpers = load_memview_c_utility("MemviewSliceIndex")
......
...@@ -710,6 +710,63 @@ static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info) { ...@@ -710,6 +710,63 @@ static CYTHON_INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info) {
__Pyx_ReleaseBuffer(info); __Pyx_ReleaseBuffer(info);
} }
/////////////// TypeInfoCompare.proto ///////////////
static int __pyx_typeinfo_cmp(__Pyx_TypeInfo *a, __Pyx_TypeInfo *b);
/////////////// TypeInfoCompare ///////////////
/* See if two dtypes are equal */
static int
__pyx_typeinfo_cmp(__Pyx_TypeInfo *a, __Pyx_TypeInfo *b)
{
int i;
if (!a || !b)
return 0;
if (a == b)
return 1;
if (a->size != b->size || a->typegroup != b->typegroup ||
a->is_unsigned != b->is_unsigned || a->ndim != b->ndim)
return 0;
if (a->ndim) {
/* Verify multidimensional C arrays */
for (i = 0; i < a->ndim; i++)
if (a->arraysize[i] != b->arraysize[i])
return 0;
}
if (a->typegroup == 'S') {
/* Check for packed struct */
if (a->flags != b->flags)
return 0;
/* compare all struct fields */
if (a->fields || b->fields) {
/* Check if both have fields */
if (!(a->fields && b->fields))
return 0;
/* compare */
for (i = 0; a->fields[i].type && b->fields[i].type; i++) {
__Pyx_StructField *field_a = a->fields + i;
__Pyx_StructField *field_b = b->fields + i;
if (field_a->offset != field_b->offset ||
!__pyx_typeinfo_cmp(field_a->type, field_b->type))
return 0;
}
/* If all fields are processed, we have a match */
return !a->fields[i].type && !b->fields[i].type;
}
}
return 1;
}
/////////////// TypeInfoToFormat.proto /////////////// /////////////// TypeInfoToFormat.proto ///////////////
struct __pyx_typeinfo_string { struct __pyx_typeinfo_string {
......
...@@ -32,6 +32,7 @@ cdef extern from *: ...@@ -32,6 +32,7 @@ cdef extern from *:
cdef struct __pyx_memoryview "__pyx_memoryview_obj": cdef struct __pyx_memoryview "__pyx_memoryview_obj":
Py_buffer view Py_buffer view
PyObject *obj PyObject *obj
__Pyx_TypeInfo *typeinfo
ctypedef struct {{memviewslice_name}}: ctypedef struct {{memviewslice_name}}:
__pyx_memoryview *memview __pyx_memoryview *memview
...@@ -58,6 +59,10 @@ cdef extern from *: ...@@ -58,6 +59,10 @@ cdef extern from *:
PyBUF_INDIRECT PyBUF_INDIRECT
PyBUF_RECORDS PyBUF_RECORDS
ctypedef struct __Pyx_TypeInfo:
pass
cdef extern from *: cdef extern from *:
ctypedef int __pyx_atomic_int ctypedef int __pyx_atomic_int
{{memviewslice_name}} slice_copy_contig "__pyx_memoryview_copy_new_contig"( {{memviewslice_name}} slice_copy_contig "__pyx_memoryview_copy_new_contig"(
...@@ -307,6 +312,7 @@ cdef class memoryview(object): ...@@ -307,6 +312,7 @@ cdef class memoryview(object):
cdef Py_buffer view cdef Py_buffer view
cdef int flags cdef int flags
cdef bint dtype_is_object cdef bint dtype_is_object
cdef __Pyx_TypeInfo *typeinfo
def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False): def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False):
self.obj = obj self.obj = obj
...@@ -328,7 +334,7 @@ cdef class memoryview(object): ...@@ -328,7 +334,7 @@ cdef class memoryview(object):
self.acquisition_count_aligned_p = <__pyx_atomic_int *> align_pointer( self.acquisition_count_aligned_p = <__pyx_atomic_int *> align_pointer(
<void *> &self.acquisition_count[0], sizeof(__pyx_atomic_int)) <void *> &self.acquisition_count[0], sizeof(__pyx_atomic_int))
self.typeinfo = NULL
def __dealloc__(memoryview self): def __dealloc__(memoryview self):
if self.obj is not None: if self.obj is not None:
...@@ -601,8 +607,14 @@ cdef class memoryview(object): ...@@ -601,8 +607,14 @@ cdef class memoryview(object):
@cname('__pyx_memoryview_new') @cname('__pyx_memoryview_new')
cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object): cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, __Pyx_TypeInfo *typeinfo):
return memoryview(o, flags, dtype_is_object) cdef memoryview result = memoryview(o, flags, dtype_is_object)
result.typeinfo = typeinfo
return result
@cname('__pyx_memoryview_check')
cdef bint memoryview_check(object o):
return isinstance(o, memoryview)
cdef tuple _unellipsify(object index, int ndim): cdef tuple _unellipsify(object index, int ndim):
""" """
...@@ -956,6 +968,7 @@ cdef memoryview_fromslice({{memviewslice_name}} *memviewslice, ...@@ -956,6 +968,7 @@ cdef memoryview_fromslice({{memviewslice_name}} *memviewslice,
__PYX_INC_MEMVIEW(memviewslice, 1) __PYX_INC_MEMVIEW(memviewslice, 1)
result.from_object = <object> memviewslice.memview.obj result.from_object = <object> memviewslice.memview.obj
result.typeinfo = memviewslice.memview.typeinfo
result.view = memviewslice.memview.view result.view = memviewslice.memview.view
result.view.buf = <void *> memviewslice.data result.view.buf = <void *> memviewslice.data
......
...@@ -89,14 +89,21 @@ static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *); ...@@ -89,14 +89,21 @@ static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *);
#define __Pyx_IS_C_CONTIG 1 #define __Pyx_IS_C_CONTIG 1
#define __Pyx_IS_F_CONTIG 2 #define __Pyx_IS_F_CONTIG 2
static int __Pyx_ValidateAndInit_memviewslice(struct __pyx_memoryview_obj *memview, static int __Pyx_ValidateAndInit_memviewslice(
int *axes_specs, int c_or_f_flag, int ndim, __Pyx_TypeInfo *dtype, int *axes_specs,
__Pyx_BufFmt_StackElem stack[], __Pyx_memviewslice *memviewslice); int c_or_f_flag,
int buf_flags,
int ndim,
__Pyx_TypeInfo *dtype,
__Pyx_BufFmt_StackElem stack[],
__Pyx_memviewslice *memviewslice,
PyObject *original_obj);
static int __Pyx_init_memviewslice( static int __Pyx_init_memviewslice(
struct __pyx_memoryview_obj *memview, struct __pyx_memoryview_obj *memview,
int ndim, int ndim,
__Pyx_memviewslice *memviewslice); __Pyx_memviewslice *memviewslice,
int memview_is_new_reference);
static CYTHON_INLINE int __pyx_add_acquisition_count_locked(__pyx_atomic_int *acquisition_count, static CYTHON_INLINE int __pyx_add_acquisition_count_locked(__pyx_atomic_int *acquisition_count,
PyThread_type_lock lock); PyThread_type_lock lock);
...@@ -116,7 +123,6 @@ static CYTHON_INLINE char *__pyx_memviewslice_index_full(const char *bufp, Py_ss ...@@ -116,7 +123,6 @@ static CYTHON_INLINE char *__pyx_memviewslice_index_full(const char *bufp, Py_ss
static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *obj) { static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *obj) {
{{memviewslice_name}} result = {{memslice_init}}; {{memviewslice_name}} result = {{memslice_init}};
struct __pyx_memoryview_obj *memview;
__Pyx_BufFmt_StackElem stack[{{struct_nesting_depth}}]; __Pyx_BufFmt_StackElem stack[{{struct_nesting_depth}}];
int axes_specs[] = { {{axes_specs}} }; int axes_specs[] = { {{axes_specs}} };
int retcode; int retcode;
...@@ -127,19 +133,16 @@ static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *obj) { ...@@ -127,19 +133,16 @@ static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *obj) {
return result; return result;
} }
memview = (struct __pyx_memoryview_obj *) __pyx_memoryview_new(obj, {{buf_flag}}, 0); retcode = __Pyx_ValidateAndInit_memviewslice(axes_specs, {{c_or_f_flag}},
if (unlikely(!memview)) {{buf_flag}}, {{ndim}},
goto __pyx_fail; &{{dtype_typeinfo}}, stack,
&result, obj);
retcode = __Pyx_ValidateAndInit_memviewslice(memview, axes_specs,
{{c_or_f_flag}}, {{ndim}}, &{{dtype_typeinfo}}, stack, &result);
if (unlikely(retcode == -1)) if (unlikely(retcode == -1))
goto __pyx_fail; goto __pyx_fail;
return result; return result;
__pyx_fail: __pyx_fail:
Py_XDECREF(memview);
result.memview = NULL; result.memview = NULL;
result.data = NULL; result.data = NULL;
return result; return result;
...@@ -148,29 +151,38 @@ __pyx_fail: ...@@ -148,29 +151,38 @@ __pyx_fail:
////////// MemviewSliceInit ////////// ////////// MemviewSliceInit //////////
static int __Pyx_ValidateAndInit_memviewslice( static int __Pyx_ValidateAndInit_memviewslice(
struct __pyx_memoryview_obj *memview,
int *axes_specs, int *axes_specs,
int c_or_f_flag, int c_or_f_flag,
int buf_flags,
int ndim, int ndim,
__Pyx_TypeInfo *dtype, __Pyx_TypeInfo *dtype,
__Pyx_BufFmt_StackElem stack[], __Pyx_BufFmt_StackElem stack[],
__Pyx_memviewslice *memviewslice) { __Pyx_memviewslice *memviewslice,
PyObject *original_obj)
{
struct __pyx_memoryview_obj *memview, *new_memview;
__Pyx_RefNannyDeclarations __Pyx_RefNannyDeclarations
Py_buffer *buf = &memview->view; Py_buffer *buf;
int stride, i, spec = 0, retval = -1; int stride, i, spec = 0, retval = -1;
__Pyx_BufFmt_Context ctx; __Pyx_BufFmt_Context ctx;
int from_memoryview = __pyx_memoryview_check(original_obj);
__Pyx_RefNannySetupContext("ValidateAndInit_memviewslice"); __Pyx_RefNannySetupContext("ValidateAndInit_memviewslice");
if (!buf) goto fail; if (from_memoryview && __pyx_typeinfo_cmp(dtype, ((struct __pyx_memoryview_obj *)
original_obj)->typeinfo)) {
if(memviewslice->data || memviewslice->memview) { /* We have a matching dtype, skip format parsing */
PyErr_SetString(PyExc_ValueError, memview = (struct __pyx_memoryview_obj *) original_obj;
"memoryviewslice struct must be initialized to NULL."); new_memview = NULL;
} else {
memview = (struct __pyx_memoryview_obj *) __pyx_memoryview_new(
original_obj, buf_flags, 0, dtype);
new_memview = memview;
if (unlikely(!memview))
goto fail; goto fail;
} }
buf = &memview->view;
if (buf->ndim != ndim) { if (buf->ndim != ndim) {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
"Buffer has wrong number of dimensions (expected %d, got %d)", "Buffer has wrong number of dimensions (expected %d, got %d)",
...@@ -178,8 +190,10 @@ static int __Pyx_ValidateAndInit_memviewslice( ...@@ -178,8 +190,10 @@ static int __Pyx_ValidateAndInit_memviewslice(
goto fail; goto fail;
} }
if (new_memview) {
__Pyx_BufFmt_Init(&ctx, stack, dtype); __Pyx_BufFmt_Init(&ctx, stack, dtype);
if (!__Pyx_BufFmt_CheckString(&ctx, buf->format)) goto fail; if (!__Pyx_BufFmt_CheckString(&ctx, buf->format)) goto fail;
}
if ((unsigned)buf->itemsize != dtype->size) { if ((unsigned)buf->itemsize != dtype->size) {
PyErr_Format(PyExc_ValueError, PyErr_Format(PyExc_ValueError,
...@@ -267,16 +281,16 @@ static int __Pyx_ValidateAndInit_memviewslice( ...@@ -267,16 +281,16 @@ static int __Pyx_ValidateAndInit_memviewslice(
} }
} }
if(unlikely(__Pyx_init_memviewslice(memview, ndim, memviewslice) == -1)) { if (unlikely(__Pyx_init_memviewslice(memview, ndim, memviewslice,
new_memview != NULL) == -1)) {
goto fail; goto fail;
} }
retval = 0; retval = 0;
goto no_fail; goto no_fail;
fail: fail:
__Pyx_XDECREF(memviewslice->memview); Py_XDECREF(new_memview);
memviewslice->memview = 0;
memviewslice->data = 0;
retval = -1; retval = -1;
no_fail: no_fail:
...@@ -287,14 +301,15 @@ no_fail: ...@@ -287,14 +301,15 @@ no_fail:
static int static int
__Pyx_init_memviewslice(struct __pyx_memoryview_obj *memview, __Pyx_init_memviewslice(struct __pyx_memoryview_obj *memview,
int ndim, int ndim,
{{memviewslice_name}} *memviewslice) {{memviewslice_name}} *memviewslice,
int memview_is_new_reference)
{ {
__Pyx_RefNannyDeclarations __Pyx_RefNannyDeclarations
int i, retval=-1; int i, retval=-1;
Py_buffer *buf = &memview->view; Py_buffer *buf = &memview->view;
__Pyx_RefNannySetupContext("init_memviewslice"); __Pyx_RefNannySetupContext("init_memviewslice");
if(!buf) { if (!buf) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"buf is NULL."); "buf is NULL.");
goto fail; goto fail;
...@@ -316,12 +331,15 @@ __Pyx_init_memviewslice(struct __pyx_memoryview_obj *memview, ...@@ -316,12 +331,15 @@ __Pyx_init_memviewslice(struct __pyx_memoryview_obj *memview,
memviewslice->memview = memview; memviewslice->memview = memview;
memviewslice->data = (char *)buf->buf; memviewslice->data = (char *)buf->buf;
__pyx_add_acquisition_count(memview); if (__pyx_add_acquisition_count(memview) == 0 && !memview_is_new_reference) {
Py_INCREF(memview);
}
retval = 0; retval = 0;
goto no_fail; goto no_fail;
fail: fail:
__Pyx_XDECREF(memviewslice->memview); /* Don't decref, the memoryview may be borrowed. Let the caller do the cleanup */
/* __Pyx_XDECREF(memviewslice->memview); */
memviewslice->memview = 0; memviewslice->memview = 0;
memviewslice->data = 0; memviewslice->data = 0;
retval = -1; retval = -1;
...@@ -486,12 +504,13 @@ __pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs, ...@@ -486,12 +504,13 @@ __pyx_memoryview_copy_new_contig(const __Pyx_memviewslice *from_mvs,
memview_obj = (struct __pyx_memoryview_obj *) __pyx_memoryview_new( memview_obj = (struct __pyx_memoryview_obj *) __pyx_memoryview_new(
(PyObject *) array_obj, contig_flag, (PyObject *) array_obj, contig_flag,
dtype_is_object); dtype_is_object,
from_mvs->memview->typeinfo);
if (unlikely(!memview_obj)) if (unlikely(!memview_obj))
goto fail; goto fail;
/* initialize new_mvs */ /* initialize new_mvs */
if (unlikely(__Pyx_init_memviewslice(memview_obj, ndim, &new_mvs) < 0)) if (unlikely(__Pyx_init_memviewslice(memview_obj, ndim, &new_mvs, 1) < 0))
goto fail; goto fail;
if (unlikely(__pyx_memoryview_copy_contents(*from_mvs, new_mvs, ndim, ndim, if (unlikely(__pyx_memoryview_copy_contents(*from_mvs, new_mvs, ndim, ndim,
......
PYTHON setup.py build_ext --inplace
PYTHON -c "import test_compare_type_pointers"
######## setup.py ########
from Cython.Build import cythonize
from distutils.core import setup
setup(
ext_modules = cythonize("*.pyx"),
)
######## test_compare_type_pointers.pyx ########
include "types.pxi"
import other_module
def test_foo_view(Foo[:] m):
return m[0].f
assert test_foo_view(other_module.fooview_obj) == 5.0
def test_double_view(double[:] m):
return m[0]
assert test_double_view(other_module.doubleview_obj) == 6.0
######## other_module.pyx ########
include "types.pxi"
cdef Foo[10] fooarray
cdef Foo[:] fooview = fooarray
fooview_obj = fooview
fooview[0].f = 5.0
cdef double[10] doublearray
cdef double[:] doubleview = doublearray
doubleview_obj = doubleview
doubleview[0] = 6.0
######## types.pxi ########
ctypedef packed struct Baz:
double d
ctypedef struct Bar:
int i
ctypedef struct Foo:
float f
double complex dc
char c
int i
Bar b
char s[20]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment