Commit dd08f821 authored by Mark Florisson's avatar Mark Florisson

Allow inter-module memoryview buffer acquiring for py < 2.6

parent b5009ce5
......@@ -570,20 +570,10 @@ class GetAndReleaseBufferUtilityCode(object):
def put_code(self, output):
code = output['utility_code_def']
proto = output['utility_code_proto']
proto_code = output['utility_code_proto']
env = output.module_node.scope
cython_scope = env.context.cython_scope
proto.put(dedent("""\
#if PY_MAJOR_VERSION < 3
static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags);
static void __Pyx_ReleaseBuffer(Py_buffer *view);
#else
#define __Pyx_GetBuffer PyObject_GetBuffer
#define __Pyx_ReleaseBuffer PyBuffer_Release
#endif
"""))
# Search all types for __getbuffer__ overloads
types = []
visited_scopes = set()
......@@ -609,51 +599,12 @@ class GetAndReleaseBufferUtilityCode(object):
find_buffer_types(env)
code.put(dedent("""
#if PY_MAJOR_VERSION < 3
static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) {
#if PY_VERSION_HEX >= 0x02060000
if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags);
#endif
"""))
if len(types) > 0:
clause = "if"
for t, get, release in types:
code.putln(" %s (PyObject_TypeCheck(obj, %s)) return %s(obj, view, flags);" % (clause, t, get))
clause = "else if"
code.putln(" else {")
code.put(dedent("""\
PyErr_Format(PyExc_TypeError, "'%100s' does not have the buffer interface", Py_TYPE(obj)->tp_name);
return -1;
""", 2))
if len(types) > 0:
code.putln(" }")
code.put(dedent("""\
}
static void __Pyx_ReleaseBuffer(Py_buffer *view) {
PyObject* obj = view->obj;
if (obj) {
#if PY_VERSION_HEX >= 0x02060000
if (PyObject_CheckBuffer(obj)) {PyBuffer_Release(view); return;}
#endif
"""))
if len(types) > 0:
clause = "if"
for t, get, release in types:
if release:
code.putln("%s (PyObject_TypeCheck(obj, %s)) %s(obj, view);" % (clause, t, release))
clause = "else if"
code.put(dedent("""
Py_DECREF(obj);
view->obj = NULL;
}
}
#endif
"""))
proto, impl = TempitaUtilityCode.load_as_string(
"GetAndReleaseBuffer", from_file="Buffer.c",
context=dict(types=types))
proto_code.putln(proto)
code.putln(impl)
def mangle_dtype_name(dtype):
......
......@@ -6,6 +6,7 @@ from Code import UtilityCode, TempitaUtilityCode
from UtilityCode import CythonUtilityCode
import Buffer
import PyrexTypes
import ModuleNode
START_ERR = "Start must not be given."
STOP_ERR = "Axis specification only allowed in the 'step' slot."
......@@ -923,7 +924,8 @@ view_utility_code = load_memview_cy_utility(
memviewslice_init_code,
is_contig_utility,
overlapping_utility,
copy_contents_new_utility],
copy_contents_new_utility,
ModuleNode.capsule_utility_code],
)
view_utility_whitelist = ('array', 'memoryview', 'array_cwrapper',
'generic', 'strided', 'indirect', 'contiguous',
......
......@@ -3072,3 +3072,5 @@ packed_struct_utility_code = UtilityCode(proto="""
#define __Pyx_PACKED
#endif
""", impl="", proto_block='utility_code_proto_before_types')
capsule_utility_code = UtilityCode.load("Capsule")
\ No newline at end of file
......@@ -8170,6 +8170,7 @@ class CnameDecoratorNode(StatNode):
e.type.objstruct_cname = self.cname + '_obj'
e.type.typeobj_cname = Naming.typeobj_prefix + self.cname
e.type.typeptr_cname = self.cname + '_type'
e.type.scope.namespace_cname = e.type.typeptr_cname
e.as_variable.cname = py_object_type.cast_code(e.type.typeptr_cname)
......
......@@ -95,6 +95,110 @@ typedef struct {
char is_valid_array;
} __Pyx_BufFmt_Context;
/////////////// GetAndReleaseBuffer.proto ///////////////
#if PY_MAJOR_VERSION < 3
static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags);
static void __Pyx_ReleaseBuffer(Py_buffer *view);
#else
#define __Pyx_GetBuffer PyObject_GetBuffer
#define __Pyx_ReleaseBuffer PyBuffer_Release
#endif
/////////////// GetAndReleaseBuffer ///////////////
#if PY_MAJOR_VERSION < 3
static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) {
PyObject *getbuffer_cobj = NULL;
#if PY_VERSION_HEX >= 0x02060000
if (PyObject_CheckBuffer(obj)) return PyObject_GetBuffer(obj, view, flags);
#endif
{{for type_ptr, getbuffer, releasebuffer in types}}
{{if getbuffer}}
if (PyObject_TypeCheck(obj, {{type_ptr}})) return {{getbuffer}}(obj, view, flags);
{{endif}}
{{endfor}}
#if PY_VERSION_HEX < 0x02060000
if (obj->ob_type->tp_dict &&
(getbuffer_cobj = PyMapping_GetItemString(obj->ob_type->tp_dict,
"__pyx_getbuffer"))) {
getbufferproc func;
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 0)
func = (getbufferproc) PyCapsule_GetPointer(getbuffer_cobj, "getbuffer(obj, view, flags)");
#else
func = (getbufferproc) PyCObject_AsVoidPtr(getbuffer_cobj);
#endif
if (!func)
goto fail;
return func(obj, view, flags);
}
#endif
PyErr_Format(PyExc_TypeError, "'%100s' does not have the buffer interface", Py_TYPE(obj)->tp_name);
#if PY_VERSION_HEX < 0x02060000
fail:
#endif
Py_XDECREF(getbuffer_cobj);
return -1;
}
static void __Pyx_ReleaseBuffer(Py_buffer *view) {
PyObject* obj = view->obj;
PyObject *releasebuffer_cobj = NULL;
if (!obj) return;
#if PY_VERSION_HEX >= 0x02060000
if (PyObject_CheckBuffer(obj)) {
PyBuffer_Release(view);
return;
}
#endif
{{for type_ptr, getbuffer, releasebuffer in types}}
{{if releasebuffer}}
if (PyObject_TypeCheck(obj, {{type_ptr}})) return {{releasebuffer}}(obj, view);
{{endif}}
{{endfor}}
#if PY_VERSION_HEX < 0x02060000
if (obj->ob_type->tp_dict &&
(releasebuffer_cobj = PyMapping_GetItemString(obj->ob_type->tp_dict,
"__pyx_releasebuffer"))) {
releasebufferproc func;
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 0)
func = (releasebufferproc) PyCapsule_GetPointer(releasebuffer_cobj, "releasebuffer(obj, view)");
#else
func = (releasebufferproc) PyCObject_AsVoidPtr(releasebuffer_cobj);
#endif
if (!func)
goto fail;
func(obj, view);
return;
}
#endif
goto nofail;
#if PY_VERSION_HEX < 0x02060000
fail:
#endif
PyErr_WriteUnraisable(obj);
nofail:
Py_XDECREF(releasebuffer_cobj);
Py_DECREF(obj);
view->obj = NULL;
}
#endif /* PY_MAJOR_VERSION < 3 */
/////////////// BufferFormatCheck.proto ///////////////
{{#
......
//////////////// Capsule.proto ////////////////
/* Todo: wrap the rest of the functionality in similar functions */
static CYTHON_INLINE PyObject *__pyx_capsule_create(void *p, const char *sig);
//////////////// Capsule ////////////////
static CYTHON_INLINE PyObject *
__pyx_capsule_create(void *p, const char *sig)
{
PyObject *cobj;
#if PY_VERSION_HEX >= 0x02070000 && !(PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 0)
cobj = PyCapsule_New(p, sig, NULL);
#else
cobj = PyCObject_FromVoidPtr(p, NULL);
#endif
return cobj;
}
......@@ -62,6 +62,9 @@ cdef extern from *:
ctypedef struct __Pyx_TypeInfo:
pass
cdef object capsule "__pyx_capsule_create" (void *p, char *sig)
cdef int __pyx_array_getbuffer(PyObject *obj, Py_buffer view, int flags)
cdef int __pyx_memoryview_getbuffer(PyObject *obj, Py_buffer view, int flags)
cdef extern from *:
ctypedef int __pyx_atomic_int
......@@ -176,6 +179,7 @@ cdef class array:
p[i] = Py_None
Py_INCREF(Py_None)
@cname('getbuffer')
def __getbuffer__(self, Py_buffer *info, int flags):
cdef int bufmode = -1
if self.mode == b"c":
......@@ -200,6 +204,8 @@ cdef class array:
info.obj = self
__pyx_getbuffer = capsule(<void *> &__pyx_array_getbuffer, "getbuffer(obj, view, flags)")
def __dealloc__(array self):
if self.callback_free_data != NULL:
self.callback_free_data(self.data)
......@@ -213,7 +219,7 @@ cdef class array:
free(self._shape)
property memview:
@cname('__pyx_cython_array_get_memview')
@cname('get_memview')
def __get__(self):
# Make this a property as 'self.data' may be set after instantiation
flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE
......@@ -352,7 +358,7 @@ cdef class memoryview(object):
return itemp
@cname('__pyx_memoryview_getitem')
#@cname('__pyx_memoryview_getitem')
def __getitem__(memoryview self, object index):
if index is Ellipsis:
return self
......@@ -366,7 +372,6 @@ cdef class memoryview(object):
itemp = self.get_item_pointer(indices)
return self.convert_item_to_object(itemp)
@cname('__pyx_memoryview_setitem')
def __setitem__(memoryview self, object index, object value):
have_slices, index = _unellipsify(index, self.view.ndim)
......@@ -466,6 +471,7 @@ cdef class memoryview(object):
for i, c in enumerate(bytesvalue):
itemp[i] = c
@cname('getbuffer')
def __getbuffer__(self, Py_buffer *info, int flags):
if flags & PyBUF_STRIDES:
info.shape = self.view.shape
......@@ -494,6 +500,8 @@ cdef class memoryview(object):
info.readonly = 0
info.obj = self
__pyx_getbuffer = capsule(<void *> &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)")
# Some properties that have the same sematics as in NumPy
property T:
@cname('__pyx_memoryview_transpose')
......@@ -946,6 +954,9 @@ cdef class _memoryviewslice(memoryview):
def __get__(self):
return self.from_object
__pyx_getbuffer = capsule(<void *> &__pyx_memoryview_getbuffer, "getbuffer(obj, view, flags)")
@cname('__pyx_memoryview_fromslice')
cdef memoryview_fromslice({{memviewslice_name}} *memviewslice,
int ndim,
......
......@@ -77,6 +77,8 @@
#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_FORMAT | PyBUF_WRITABLE)
#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_FORMAT | PyBUF_WRITABLE)
typedef int (*getbufferproc)(PyObject *, Py_buffer *, int);
typedef void (*releasebufferproc)(PyObject *, Py_buffer *);
#endif
#if PY_MAJOR_VERSION < 3
......
......@@ -19,7 +19,16 @@ def test_foo_view(Foo[:] m):
return m[0].f
assert test_foo_view(other_module.fooview_obj) == 5.0
assert test_foo_view(other_module.otherfooview_obj) == 4.0
# Test for type comparison where the memoryview instance check succeeds
cdef OtherFoo[10] otherfooarray
cdef OtherFoo[:] otherfooview = otherfooarray
otherfooview_obj = otherfooview
otherfooview[0].f = 4.0
assert test_foo_view(otherfooview_obj) == 4.0
# Test a simple dtype now
def test_double_view(double[:] m):
return m[0]
......@@ -34,6 +43,12 @@ fooview_obj = fooview
fooview[0].f = 5.0
cdef OtherFoo[10] otherfooarray
cdef OtherFoo[:] otherfooview = otherfooarray
otherfooview_obj = otherfooview
otherfooview[0].f = 4.0
cdef double[10] doublearray
cdef double[:] doubleview = doublearray
doubleview_obj = doubleview
......@@ -54,3 +69,11 @@ ctypedef struct Foo:
int i
Bar b
char s[20]
ctypedef struct OtherFoo:
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