Buffers: Better Py2.6 support (ticket 62)
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Thu, 4 Sep 2008 11:25:09 +0000 (13:25 +0200)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Thu, 4 Sep 2008 11:25:09 +0000 (13:25 +0200)
Cython/Compiler/Buffer.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/TypeSlots.py

index ea5f167fc689e4e63d26957277f9a638ede2974c..41b5ee11948947d20cb936a4b02142d3f2dbc5de 100644 (file)
@@ -566,6 +566,9 @@ def buffer_type_checker(dtype, code):
     return funcname
 
 def use_py2_buffer_functions(env):
+    # Emulation of PyObject_GetBuffer and PyBuffer_Release for Python 2.
+    # For >= 2.6 we do double mode -- use the new buffer interface on objects
+    # which has the right tp_flags set, but emulation otherwise.
     codename = "PyObject_GetBuffer" # just a representative unique key
 
     # Search all types for __getbuffer__ overloads
@@ -586,8 +589,12 @@ def use_py2_buffer_functions(env):
     find_buffer_types(env)
 
     code = dedent("""
-        #if (PY_MAJOR_VERSION < 3) && !(Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_NEWBUFFER)
+        #if PY_MAJOR_VERSION < 3
         static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags) {
+          #if PY_VERSION_HEX >= 0x02060000
+          if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER)
+              return PyObject_GetBuffer(obj, view, flags);
+          #endif
     """)
     if len(types) > 0:
         clause = "if"
@@ -623,7 +630,7 @@ def use_py2_buffer_functions(env):
     """)
                    
     env.use_utility_code([dedent("""\
-        #if (PY_MAJOR_VERSION < 3) && !(Py_TPFLAGS_DEFAULT & Py_TPFLAGS_HAVE_NEWBUFFER)
+        #if PY_MAJOR_VERSION < 3
         static int __Pyx_GetBuffer(PyObject *obj, Py_buffer *view, int flags);
         static void __Pyx_ReleaseBuffer(Py_buffer *view);
         #else
index f2987cecaa683fc085a21065992adcc2f21138a5..6beaa6fa4d7ce69b8a24f07fb9c599a9cfc5afd2 100644 (file)
@@ -461,6 +461,10 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         code.putln("  #define Py_TPFLAGS_HAVE_INDEX 0")
         code.putln("#endif")
 
+        code.putln("#if (PY_VERSION_HEX < 0x02060000) || (PY_MAJOR_VERSION >= 3)")
+        code.putln("  #define Py_TPFLAGS_HAVE_NEWBUFFER 0")
+        code.putln("#endif")
+
         code.putln("#if PY_MAJOR_VERSION >= 3")
         code.putln("  #define PyBaseString_Type            PyUnicode_Type")
         code.putln("  #define PyString_Type                PyBytes_Type")
index a5898c97961e530fa824c2a7edb5bd3b632e4723..d62f1cc213fec45ddfa26af6185a22b2ef571f6c 100644 (file)
@@ -127,13 +127,15 @@ class SlotDescriptor:
     #  flag                          Py_TPFLAGS_XXX value indicating presence of slot
     #  py3k                          Indicates presence of slot in Python 3
     #  py2                           Indicates presence of slot in Python 2
+    #  ifdef                         Full #ifdef string that slot is wrapped in. Using this causes py3k, py2 and flags to be ignored.)
 
-    def __init__(self, slot_name, dynamic = 0, flag = None, py3k = True, py2 = True):
+    def __init__(self, slot_name, dynamic = 0, flag = None, py3k = True, py2 = True, ifdef = None):
         self.slot_name = slot_name
         self.is_initialised_dynamically = dynamic
         self.flag = flag
         self.py3k = py3k
         self.py2  = py2
+        self.ifdef = ifdef
 
     def generate(self, scope, code):
         if self.is_initialised_dynamically:
@@ -143,16 +145,17 @@ class SlotDescriptor:
         flag = self.flag
         py3k = self.py3k
         py2  = self.py2
-        if not py3k:
-            code.putln("#if PY_MAJOR_VERSION < 3")
-        elif not py2:
-            code.putln("#if PY_MAJOR_VERSION >= 3")
-        if flag:
-            code.putln("#if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & %s)" % flag)
+        if self.ifdef:
+            code.putln("#if %s" % self.ifdef)
+        else:
+            if not py3k:
+                code.putln("#if PY_MAJOR_VERSION < 3")
+            elif not py2:
+                code.putln("#if PY_MAJOR_VERSION >= 3")
+            if flag:
+                code.putln("#if (PY_MAJOR_VERSION >= 3) || (Py_TPFLAGS_DEFAULT & %s)" % flag)
         code.putln("%s, /*%s*/" % (value, self.slot_name))
-        if flag:
-            code.putln("#endif")
-        if not py3k or not py2:
+        if flag or (not py3k or not py2) or self.ifdef:
             code.putln("#endif")
 
     # Some C implementations have trouble statically 
@@ -199,8 +202,8 @@ class MethodSlot(SlotDescriptor):
     #  method_name  string           The __xxx__ name of the method
     #  default      string or None   Default value of the slot
     
-    def __init__(self, signature, slot_name, method_name, default = None, flag = None, py3k=True, py2=True):
-        SlotDescriptor.__init__(self, slot_name, flag = flag, py3k = py3k, py2=py2)
+    def __init__(self, signature, slot_name, method_name, default = None, flag = None, py3k=True, py2=True, ifdef=None):
+        SlotDescriptor.__init__(self, slot_name, flag = flag, py3k = py3k, py2=py2, ifdef=ifdef)
         self.signature = signature
         self.slot_name = slot_name
         self.method_name = method_name
@@ -296,7 +299,7 @@ class TypeFlagsSlot(SlotDescriptor):
     #  Descriptor for the type flags slot.
     
     def slot_code(self, scope):
-        value = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE"
+        value = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_NEWBUFFER"
         if scope.needs_gc():
             value += "|Py_TPFLAGS_HAVE_GC"
         return value
@@ -609,8 +612,8 @@ PyBufferProcs = (
     MethodSlot(getsegcountproc, "bf_getsegcount", "__getsegcount__", py3k = False),
     MethodSlot(getcharbufferproc, "bf_getcharbuffer", "__getcharbuffer__", py3k = False),
 
-    MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__", flag = "Py_TPFLAGS_HAVE_NEWBUFFER"),
-    MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__", flag = "Py_TPFLAGS_HAVE_NEWBUFFER"),
+    MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000"),
+    MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__", ifdef = "PY_VERSION_HEX >= 0x02060000")
 )
 
 #------------------------------------------------------------------------------------------