Author: Matti Picus <[email protected]>
Branch: issue2444
Changeset: r89189:75e80dab0448
Date: 2016-12-19 20:27 +0200
http://bitbucket.org/pypy/pypy/changeset/75e80dab0448/

Log:    create PyMemoryViewObject with a Py_buffer view, change Py_buffer ->
        rffi.CStruct

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -630,25 +630,27 @@
 PyVarObjectStruct = cpython_struct("PyVarObject", PyVarObjectFields)
 PyVarObject = lltype.Ptr(PyVarObjectStruct)
 
-Py_buffer = cpython_struct(
-    "Py_buffer", (
+Py_buffer = rffi.CStruct( "Py_buffer", 
         ('buf', rffi.VOIDP),
         ('obj', PyObject),
         ('len', Py_ssize_t),
         ('itemsize', Py_ssize_t),
 
-        ('readonly', lltype.Signed),
-        ('ndim', lltype.Signed),
+        ('readonly', rffi.INT_real),
+        ('ndim', rffi.INT_real),
         ('format', rffi.CCHARP),
         ('shape', Py_ssize_tP),
         ('strides', Py_ssize_tP),
+        ('suboffsets', Py_ssize_tP),
         ('_format', rffi.CFixedArray(rffi.UCHAR, Py_MAX_FMT)),
         ('_shape', rffi.CFixedArray(Py_ssize_t, Py_MAX_NDIMS)),
         ('_strides', rffi.CFixedArray(Py_ssize_t, Py_MAX_NDIMS)),
-        ('suboffsets', Py_ssize_tP),
         #('smalltable', rffi.CFixedArray(Py_ssize_t, 2)),
-        ('internal', rffi.VOIDP)
-        ))
+        ('internal', rffi.VOIDP),
+        hints={'size': 6 * rffi.sizeof(Py_ssize_tP) + 2 * 
rffi.sizeof(Py_ssize_t) +
+                       2 * rffi.sizeof(rffi.INT_real) + 
rffi.sizeof(rffi.CCHARP) +
+                       Py_MAX_FMT * rffi.sizeof(rffi.UCHAR) +
+                       2 * Py_MAX_NDIMS * rffi.sizeof(Py_ssize_t)})
 Py_bufferP = lltype.Ptr(Py_buffer)
 
 @specialize.memo()
diff --git a/pypy/module/cpyext/classobject.py 
b/pypy/module/cpyext/classobject.py
--- a/pypy/module/cpyext/classobject.py
+++ b/pypy/module/cpyext/classobject.py
@@ -1,7 +1,7 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
     PyObjectFields, CANNOT_FAIL,
-    cpython_api, bootstrap_function, cpython_struct, build_type_checkers)
+    cpython_api, bootstrap_function, build_type_checkers)
 from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref, 
Py_DecRef, make_typedescr
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
 from pypy.module.__builtin__.interp_classobj import W_ClassObject, 
W_InstanceObject
diff --git a/pypy/module/cpyext/include/memoryobject.h 
b/pypy/module/cpyext/include/memoryobject.h
--- a/pypy/module/cpyext/include/memoryobject.h
+++ b/pypy/module/cpyext/include/memoryobject.h
@@ -5,6 +5,14 @@
 extern "C" {
 #endif
 
+/* The struct is declared here but it shouldn't
+   be considered public. Don't access those fields directly,
+   use the functions instead! */
+typedef struct {
+    PyObject_HEAD
+    Py_buffer view;
+} PyMemoryViewObject;
+
 
 
 
diff --git a/pypy/module/cpyext/include/object.h 
b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -145,7 +145,7 @@
 /* Py3k buffer interface, adapted for PyPy */
 #define Py_MAX_NDIMS 32
 #define Py_MAX_FMT 128
-typedef struct bufferinfo {
+typedef struct Py_buffer {
     void *buf;
     PyObject *obj;        /* owned reference */
     Py_ssize_t len;
diff --git a/pypy/module/cpyext/memoryobject.py 
b/pypy/module/cpyext/memoryobject.py
--- a/pypy/module/cpyext/memoryobject.py
+++ b/pypy/module/cpyext/memoryobject.py
@@ -1,14 +1,57 @@
 from pypy.module.cpyext.api import (cpython_api, Py_buffer, CANNOT_FAIL,
-                         Py_MAX_FMT, Py_MAX_NDIMS, build_type_checkers, 
Py_ssize_tP)
-from pypy.module.cpyext.pyobject import PyObject, make_ref, incref, from_ref
+                         Py_MAX_FMT, Py_MAX_NDIMS, build_type_checkers,
+                         Py_ssize_tP, PyObjectFields, cpython_struct,
+                         bootstrap_function, Py_bufferP)
+from pypy.module.cpyext.pyobject import (PyObject, make_ref, as_pyobj, incref,
+             decref, from_ref, make_typedescr)
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.rlib.rarithmetic import widen
 from pypy.objspace.std.memoryobject import W_MemoryView
+from pypy.module.cpyext.object import _dealloc
 from pypy.module.cpyext.import_ import PyImport_Import
 
-PyMemoryView_Check, PyMemoryView_CheckExact = 
build_type_checkers("MemoryView", "w_memoryview")
+PyMemoryView_Check, PyMemoryView_CheckExact = build_type_checkers("MemoryView")
 
-@cpython_api([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real],
+
+PyMemoryViewObjectStruct = lltype.ForwardReference()
+PyMemoryViewObject = lltype.Ptr(PyMemoryViewObjectStruct)
+PyMemoryViewObjectFields = PyObjectFields + \
+    (("view", Py_buffer),)
+cpython_struct("PyMemoryViewObject", PyMemoryViewObjectFields, 
PyMemoryViewObjectStruct)
+
+@bootstrap_function
+def init_memoryobject(space):
+    "Type description of PyDictObject"
+    make_typedescr(W_MemoryView.typedef,
+                   basestruct=PyMemoryViewObject.TO,
+                   attach=memory_attach,
+                   dealloc=memory_dealloc,
+                   #realize=memory_realize,
+                  )
+
+def memory_attach(space, py_obj, w_obj, w_userdata=None):
+    """
+    Fills a newly allocated PyMemoryViewObject with the given W_MemoryView 
object.
+    """
+    py_obj = rffi.cast(PyMemoryViewObject, py_obj)
+    py_obj.c_view.c_obj = rffi.cast(PyObject, 0)
+
+def memory_realize(space, py_obj):
+    """
+    Creates the memory object in the interpreter
+    """
+    raise oefmt(space.w_NotImplementedError, "cannot call this yet")
+
+@cpython_api([PyObject], lltype.Void, header=None)
+def memory_dealloc(space, py_obj):
+    mem_obj = rffi.cast(PyMemoryViewObject, py_obj)
+    if mem_obj.c_view.c_obj:
+        decref(space, mem_obj.c_view.c_obj)
+    mem_obj.c_view.c_obj = rffi.cast(PyObject, 0)
+    _dealloc(space, py_obj)
+
+
+@cpython_api([PyObject, Py_bufferP, rffi.INT_real],
              rffi.INT_real, error=-1)
 def PyObject_GetBuffer(space, w_obj, view, flags):
     """Export obj into a Py_buffer, view.  These arguments must
@@ -111,7 +154,7 @@
         sd *= dim
     return 1
 
-@cpython_api([lltype.Ptr(Py_buffer), lltype.Char], rffi.INT_real, 
error=CANNOT_FAIL)
+@cpython_api([Py_bufferP, lltype.Char], rffi.INT_real, error=CANNOT_FAIL)
 def PyBuffer_IsContiguous(space, view, fort):
     """Return 1 if the memory defined by the view is C-style (fort is
     'C') or Fortran-style (fort is 'F') contiguous or either one
@@ -132,7 +175,7 @@
 def PyMemoryView_FromObject(space, w_obj):
     return space.call_method(space.builtin, "memoryview", w_obj)
 
-@cpython_api([lltype.Ptr(Py_buffer)], PyObject)
+@cpython_api([Py_bufferP], PyObject)
 def PyMemoryView_FromBuffer(space, view):
     """Create a memoryview object wrapping the given buffer-info structure 
view.
     The memoryview object then owns the buffer, which means you shouldn't
@@ -149,14 +192,15 @@
     # XXX needed for numpy on py3k
     raise NotImplementedError('PyMemoryView_GET_BASE')
 
-@cpython_api([PyObject], lltype.Ptr(Py_buffer), error=CANNOT_FAIL)
+@cpython_api([PyObject], Py_bufferP, error=CANNOT_FAIL)
 def PyMemoryView_GET_BUFFER(space, w_obj):
     """Return a pointer to the buffer-info structure wrapped by the given
     object.  The object must be a memoryview instance; this macro doesn't
     check its type, you must do it yourself or you will risk crashes."""
-    view = lltype.malloc(Py_buffer, flavor='raw', zero=True)
     if not isinstance(w_obj, W_MemoryView):
-        return view
+        return lltype.nullptr(Py_buffer)
+    py_memobj = rffi.cast(PyMemoryViewObject, as_pyobj(space, w_obj)) # no 
inc_ref
+    view = py_memobj.c_view
     ndim = w_obj.buf.getndim()
     if ndim >= Py_MAX_NDIMS:
         # XXX warn?
@@ -173,8 +217,5 @@
         view.c_buf = rffi.cast(rffi.VOIDP, rffi.str2charp(space.str_w(w_s), 
track_allocation=False))
         rffi.setintfield(view, 'c_readonly', 1)
         isstr = True
-    # XXX leaks the view object and never decrefs the view.c_obj
-    #     In cpython the view is a field of the PyMemoryViewObject
-    #     and view.obj is decrefed in memory_dealloc
     return view
 
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -356,7 +356,7 @@
             with lltype.scoped_alloc(Py_buffer) as pybuf:
                 pybuf.c_buf = self.ptr
                 pybuf.c_len = self.size
-                pybuf.c_ndim = rffi.cast(rffi.INT, self.ndim)
+                pybuf.c_ndim = rffi.cast(rffi.INT_real, self.ndim)
                 for i in range(self.ndim):
                     pybuf.c_shape[i] = self.shape[i]
                     pybuf.c_strides[i] = self.strides[i]
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -10,11 +10,7 @@
 PyMethodDef = rffi.VOIDP
 PyGetSetDef = rffi.VOIDP
 PyMemberDef = rffi.VOIDP
-Py_buffer = rffi.VOIDP
 va_list = rffi.VOIDP
-PyDateTime_Date = rffi.VOIDP
-PyDateTime_DateTime = rffi.VOIDP
-PyDateTime_Time = rffi.VOIDP
 wrapperbase = rffi.VOIDP
 FILE = rffi.VOIDP
 PyFileObject = rffi.VOIDP
diff --git a/pypy/module/cpyext/test/buffer_test.c 
b/pypy/module/cpyext/test/buffer_test.c
--- a/pypy/module/cpyext/test/buffer_test.c
+++ b/pypy/module/cpyext/test/buffer_test.c
@@ -190,19 +190,21 @@
 {
     Py_buffer* view = NULL;
     PyObject* obj = PyTuple_GetItem(args, 0);
+    int retval = 0;
     int before_cnt = obj->ob_refcnt;
     PyObject* memoryview = PyMemoryView_FromObject(obj);
     if (memoryview == NULL)
         return PyInt_FromLong(-1);
     view = PyMemoryView_GET_BUFFER(memoryview);
-    Py_DECREF(memoryview);
+    retval = view->len;
+    Py_DECREF(memoryview); /* view is no longer valid */
     if (obj->ob_refcnt != before_cnt)
     {
         PyErr_SetString(PyExc_RuntimeError,
             "leaking view->obj from PyMemoryView_GET_BUFFER");
         return NULL;
     }
-    return PyInt_FromLong(view->len);
+    return PyInt_FromLong(retval);
 }
 
 /* Copied from numpy tests */
diff --git a/pypy/module/cpyext/test/test_memoryobject.py 
b/pypy/module/cpyext/test/test_memoryobject.py
--- a/pypy/module/cpyext/test/test_memoryobject.py
+++ b/pypy/module/cpyext/test/test_memoryobject.py
@@ -20,16 +20,16 @@
     def test_frombuffer(self, space, api):
         w_buf = space.newbuffer(StringBuffer("hello"))
         w_memoryview = api.PyMemoryView_FromObject(w_buf)
-        w_view = api.PyMemoryView_GET_BUFFER(w_memoryview)
-        assert w_view.c_ndim == 1
-        f = rffi.charp2str(w_view.c_format)
+        view = api.PyMemoryView_GET_BUFFER(w_memoryview)
+        assert view.c_ndim == 1
+        f = rffi.charp2str(view.c_format)
         assert f == 'B'
-        assert w_view.c_shape[0] == 5
-        assert w_view.c_strides[0] == 1
-        assert w_view.c_len == 5
-        o = rffi.charp2str(w_view.c_buf)
+        assert view.c_shape[0] == 5
+        assert view.c_strides[0] == 1
+        assert view.c_len == 5
+        o = rffi.charp2str(view.c_buf)
         assert o == 'hello'
-        w_mv = api.PyMemoryView_FromBuffer(w_view)
+        w_mv = api.PyMemoryView_FromBuffer(view)
         for f in ('format', 'itemsize', 'ndim', 'readonly', 
                   'shape', 'strides', 'suboffsets'):
             w_f = space.wrap(f)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to