Updated buffers to beta 3 of Py3
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Mon, 25 Aug 2008 14:09:31 +0000 (16:09 +0200)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Mon, 25 Aug 2008 14:09:31 +0000 (16:09 +0200)
Cython/Compiler/Buffer.py
Cython/Compiler/Builtin.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/Nodes.py
Cython/Includes/numpy.pxd
tests/run/bufaccess.pyx
tests/run/buffer.pyx

index 637a11c843c64409b392af44fed43e293849cc9d..ea5f167fc689e4e63d26957277f9a638ede2974c 100644 (file)
@@ -242,9 +242,7 @@ def put_acquire_arg_buffer(entry, code, pos):
 #        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):
@@ -274,8 +272,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buffer_aux, buffer_type,
 
     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))
@@ -606,7 +603,9 @@ def use_py2_buffer_functions(env):
     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"
@@ -615,6 +614,9 @@ def use_py2_buffer_functions(env):
                 code += "%s (PyObject_TypeCheck(obj, %s)) %s(obj, view);" % (clause, t, release)
                 clause = "else if"
     code += dedent("""
+            Py_DECREF(obj);
+            view->obj = NULL;
+          }
         }
 
         #endif
@@ -623,10 +625,10 @@ def use_py2_buffer_functions(env):
     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)
 
@@ -655,20 +657,21 @@ static void __Pyx_RaiseBufferIndexError(int axis) {
 # 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;
index 3c468fe005401c52b44e670c8486e632aae7da4c..3d11eeb9de6ea367333308dd758ea2a48bf59d27 100644 (file)
@@ -104,14 +104,15 @@ builtin_types_table = [
 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),
       ])
 ]
index 23cb11455dd48f4334f9dba64ccb5b8d78455fa5..d7fb6b1cf9c23b2f3c71ad2be8ede3566e747e7f 100644 (file)
@@ -429,14 +429,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         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("")
index d3596ea21daee478ba6c0b042ae2f6084bb9472f..ce0cb38a92f1bae9608fe7450b1be34ccffce492 100644 (file)
@@ -860,6 +860,9 @@ class FuncDefNode(StatNode, BlockNode):
 
         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()
@@ -902,6 +905,9 @@ class FuncDefNode(StatNode, BlockNode):
         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 
@@ -971,17 +977,27 @@ class FuncDefNode(StatNode, BlockNode):
                     "%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:
@@ -1042,8 +1058,27 @@ class FuncDefNode(StatNode, BlockNode):
         # 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.
index db7d4b9c05303f1c800130f02088f72aada26200..5d9874182d396fbec74c6dae699d8b109ed52271 100644 (file)
@@ -43,6 +43,7 @@ cdef extern from "numpy/arrayobject.h":
                 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)
index f0f3e04f89ffa657dde2b80b20cf95fe13183d17..4bfb8186cadd9986f609d8289927d38753e2f971 100644 (file)
@@ -25,11 +25,11 @@ setup_string = u"""
 
 """
     
-def testcase(func):
+def testcase2(func):
     __test__[func.__name__] = setup_string + func.__doc__
     return func
 
-def testcas(a):
+def testcase(a):
     pass
 
 
@@ -50,7 +50,7 @@ def printbuf():
     cdef object[int, ndim=2] buf
     print buf
 
-@testcase
+@testcase2
 def acquire_release(o1, o2):
     """
     >>> acquire_release(A, B)
@@ -949,11 +949,10 @@ cdef class MockBuffer:
     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:
@@ -961,6 +960,7 @@ cdef class MockBuffer:
                 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
index be93bfad27ea18792803d09e09f0d91aab28dc52..07d344e1ad2dbfb518e654f8d3a71b5e5ba6d0b4 100644 (file)
@@ -8,18 +8,16 @@ if sys.version_info[0] >= 3:
     __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
@@ -30,10 +28,8 @@ s = "abcdefg"
 
 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"
@@ -46,7 +42,4 @@ cdef class TestBuffer:
 
 cdef class TestBufferRelease(TestBuffer):
     def __releasebuffer__(self, Py_buffer* buffer):
-        if buffer is NULL:
-            print u"unlocking!"
-        else:
-            print u"releasing!"
+        print u"releasing!"