# entry.buffer_aux.buffer_info_var.cname))
def get_release_buffer_code(entry):
- return "__Pyx_SafeReleaseBuffer((PyObject*)%s, &%s)" % (
- entry.cname,
- entry.buffer_aux.buffer_info_var.cname)
+ return "__Pyx_SafeReleaseBuffer(&%s)" % entry.buffer_aux.buffer_info_var.cname
def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type,
is_initialized, pos, code):
if is_initialized:
# Release any existing buffer
- code.putln('__Pyx_SafeReleaseBuffer((PyObject*)%s, &%s);' % (
- lhs_cname, bufstruct))
+ code.putln('__Pyx_SafeReleaseBuffer(&%s);' % bufstruct)
# Acquire
retcode_cname = code.funcstate.allocate_temp(PyrexTypes.c_int_type)
code.putln("%s = %s;" % (retcode_cname, getbuffer % rhs_cname))
code += dedent("""
}
- static void __Pyx_ReleaseBuffer(PyObject *obj, Py_buffer *view) {
+ static void __Pyx_ReleaseBuffer(Py_buffer *view) {
+ PyObject* obj = view->obj;
+ if (obj) {
""")
if len(types) > 0:
clause = "if"
code += "%s (PyObject_TypeCheck(obj, %s)) %s(obj, view);" % (clause, t, release)
clause = "else if"
code += dedent("""
+ Py_DECREF(obj);
+ view->obj = NULL;
+ }
}
#endif
env.use_utility_code([dedent("""\
#if (PY_MAJOR_VERSION < 3) && !(Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_NEWBUFFER)
static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags);
- static void __Pyx_ReleaseBuffer(PyObject *obj, Py_buffer *view);
+ static void __Pyx_ReleaseBuffer(Py_buffer *view);
#else
#define __Pyx_GetBuffer PyObject_GetBuffer
- #define __Pyx_ReleaseBuffer PyObject_ReleaseBuffer
+ #define __Pyx_ReleaseBuffer PyBuffer_Release
#endif
"""), code], codename)
# exporter.
#
acquire_utility_code = ["""\
-static INLINE void __Pyx_SafeReleaseBuffer(PyObject* obj, Py_buffer* info);
+static INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info);
static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf); /*proto*/
static INLINE const char* __Pyx_ConsumeWhitespace(const char* ts); /*proto*/
static INLINE const char* __Pyx_BufferTypestringCheckEndian(const char* ts); /*proto*/
static void __Pyx_BufferNdimError(Py_buffer* buffer, int expected_ndim); /*proto*/
""", """
-static INLINE void __Pyx_SafeReleaseBuffer(PyObject* obj, Py_buffer* info) {
+static INLINE void __Pyx_SafeReleaseBuffer(Py_buffer* info) {
if (info->buf == NULL) return;
if (info->suboffsets == __Pyx_minusones) info->suboffsets = NULL;
- __Pyx_ReleaseBuffer(obj, info);
+ __Pyx_ReleaseBuffer(info);
}
static INLINE void __Pyx_ZeroBuffer(Py_buffer* buf) {
buf->buf = NULL;
+ buf->obj = NULL;
buf->strides = __Pyx_zeros;
buf->shape = __Pyx_zeros;
buf->suboffsets = __Pyx_minusones;
builtin_structs_table = [
('Py_buffer', 'Py_buffer',
[("buf", PyrexTypes.c_void_ptr_type),
+ ("obj", PyrexTypes.py_object_type),
("len", PyrexTypes.c_py_ssize_t_type),
+ ("itemsize", PyrexTypes.c_py_ssize_t_type),
("readonly", PyrexTypes.c_bint_type),
- ("format", PyrexTypes.c_char_ptr_type),
("ndim", PyrexTypes.c_int_type),
+ ("format", PyrexTypes.c_char_ptr_type),
("shape", PyrexTypes.c_py_ssize_t_ptr_type),
("strides", PyrexTypes.c_py_ssize_t_ptr_type),
("suboffsets", PyrexTypes.c_py_ssize_t_ptr_type),
- ("itemsize", PyrexTypes.c_py_ssize_t_type),
("internal", PyrexTypes.c_void_ptr_type),
])
]
code.putln("")
code.putln(" typedef struct {")
code.putln(" void *buf;")
+ code.putln(" PyObject *obj;")
code.putln(" Py_ssize_t len;")
+ code.putln(" Py_ssize_t itemsize;")
code.putln(" int readonly;")
- code.putln(" const char *format;")
code.putln(" int ndim;")
+ code.putln(" char *format;")
code.putln(" Py_ssize_t *shape;")
code.putln(" Py_ssize_t *strides;")
code.putln(" Py_ssize_t *suboffsets;")
- code.putln(" Py_ssize_t itemsize;")
code.putln(" void *internal;")
code.putln(" } Py_buffer;")
code.putln("")
lenv = self.local_scope
+ is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
+ self.entry.scope.is_c_class_scope)
+
# Generate C code for header and body of function
code.enter_cfunc_scope()
code.return_from_error_cleanup_label = code.new_label()
acquire_gil = self.need_gil_acquisition(lenv)
if acquire_gil:
code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
+ # ----- Automatic lead-ins for certain special functions
+ if is_getbuffer_slot:
+ self.getbuffer_init(code)
# ----- Fetch arguments
self.generate_argument_parsing_code(env, code)
# If an argument is assigned to in the body, we must
"%s = %s;" % (
Naming.retval_cname,
err_val))
- if buffers_present:
- # Else, non-error return will be an empty clause
+
+ if is_getbuffer_slot:
+ self.getbuffer_error_cleanup(code)
+
+ # If we are using the non-error cleanup section we should
+ # jump past it if we have an error. The if-test below determine
+ # whether this section is used.
+ if buffers_present or is_getbuffer_slot:
code.put_goto(code.return_from_error_cleanup_label)
+
# ----- Non-error return cleanup
- # PS! If adding something here, modify the conditions for the
- # goto statement in error cleanup above
+ # If you add anything here, remember to add a condition to the
+ # if-test above in the error block (so that it can jump past this
+ # block).
code.put_label(code.return_label)
for entry in lenv.buffer_entries:
if entry.used:
code.putln("%s;" % Buffer.get_release_buffer_code(entry))
+ if is_getbuffer_slot:
+ self.getbuffer_normal_cleanup(code)
# ----- Return cleanup for both error and no-error return
code.put_label(code.return_from_error_cleanup_label)
if not Options.init_local_none:
# For Python class methods, create and store function object
if self.assmt:
self.assmt.generate_execution_code(code)
-
+ #
+ # Special code for the __getbuffer__ call
+ #
+ def getbuffer_init(self, code):
+ info = self.local_scope.arg_entries[1].cname
+ # Python 3.0 betas have a bug in memoryview which makes it call
+ # getbuffer with a NULL parameter. For now we work around this;
+ # the following line should be removed when this bug is fixed.
+ code.putln("if (%s == NULL) return 0;" % info)
+ code.putln("%s->obj = Py_None; Py_INCREF(Py_None);" % info)
+
+ def getbuffer_error_cleanup(self, code):
+ info = self.local_scope.arg_entries[1].cname
+ code.putln("Py_DECREF(%s->obj); %s->obj = NULL;" %
+ (info, info))
+
+ def getbuffer_normal_cleanup(self, code):
+ info = self.local_scope.arg_entries[1].cname
+ code.putln("if (%s->obj == Py_None) { Py_DECREF(Py_None); %s->obj = NULL; }" %
+ (info, info))
class CFuncDefNode(FuncDefNode):
# C function definition.
raise RuntimeError("Py_intptr_t and Py_ssize_t differs in size, numpy.pxd does not support this")
info.buf = PyArray_DATA(self)
+ # info.obj = None # this is automatic
info.ndim = PyArray_NDIM(self)
info.strides = <Py_ssize_t*>PyArray_STRIDES(self)
info.shape = <Py_ssize_t*>PyArray_DIMS(self)
"""
-def testcase(func):
+def testcase2(func):
__test__[func.__name__] = setup_string + func.__doc__
return func
-def testcas(a):
+def testcase(a):
pass
cdef object[int, ndim=2] buf
print buf
-@testcase
+@testcase2
def acquire_release(o1, o2):
"""
>>> acquire_release(A, B)
def __getbuffer__(MockBuffer self, Py_buffer* buffer, int flags):
if self.fail:
raise ValueError("Failing on purpose")
-
- if buffer is NULL:
- print u"locking!"
- return
+ if buffer == NULL:
+ return
+
self.recieved_flags = []
cdef int value
for name, value in available_flags:
self.recieved_flags.append(name)
buffer.buf = <void*>(<char*>self.buffer + (<int>self.offset * self.itemsize))
+ buffer.obj = self
buffer.len = self.len
buffer.readonly = 0
buffer.format = <char*>self.format
__doc__ += u"""
>>> ms = memoryview(s)
>>> ms.tobytes()
-bytearray(b'abcdefg')
+b'abcdefg'
>>> m1 = memoryview(b1)
>>> m1.tobytes()
-locking!
-bytearray(b'abcdefg')
+b'abcdefg'
>>> m2 = memoryview(b2)
>>> m2.tobytes()
-locking!
-unlocking!
-bytearray(b'abcdefg')
+releasing!
+b'abcdefg'
>>> del m1
>>> del m2
cdef class TestBuffer:
def __getbuffer__(self, Py_buffer* buffer, int flags):
- if buffer is NULL:
- print u"locking!"
- return
buffer.buf = <char*>s
+ buffer.obj = self
buffer.len = len(s)
buffer.readonly = 0
buffer.format = "B"
cdef class TestBufferRelease(TestBuffer):
def __releasebuffer__(self, Py_buffer* buffer):
- if buffer is NULL:
- print u"unlocking!"
- else:
- print u"releasing!"
+ print u"releasing!"