[pypy-commit] pypy default: Merge branch pyarg-parsetuple-s-star-buffer:

amauryfa noreply at buildbot.pypy.org
Tue Dec 20 23:19:13 CET 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: 
Changeset: r50788:5d4dfac3c59a
Date: 2011-12-20 23:18 +0100
http://bitbucket.org/pypy/pypy/changeset/5d4dfac3c59a/

Log:	Merge branch pyarg-parsetuple-s-star-buffer: (exarkun) Add support
	for "buffer()" objects in cpyext. They also implement the C buffer
	interface.

diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -45,6 +45,8 @@
 import pypy.module.cpyext.longobject
 import pypy.module.cpyext.listobject
 import pypy.module.cpyext.sequence
+import pypy.module.cpyext.buffer
+import pypy.module.cpyext.bufferobject
 import pypy.module.cpyext.eval
 import pypy.module.cpyext.import_
 import pypy.module.cpyext.mapping
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
@@ -317,6 +317,10 @@
 
 INTERPLEVEL_API = {}
 FUNCTIONS = {}
+
+# These are C symbols which cpyext will export, but which are defined in .c
+# files somewhere in the implementation of cpyext (rather than being defined in
+# RPython).
 SYMBOLS_C = [
     'Py_FatalError', 'PyOS_snprintf', 'PyOS_vsnprintf', 'PyArg_Parse',
     'PyArg_ParseTuple', 'PyArg_UnpackTuple', 'PyArg_ParseTupleAndKeywords',
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/buffer.py
@@ -0,0 +1,11 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import (
+    cpython_api, CANNOT_FAIL, Py_buffer)
+
+ at cpython_api([lltype.Ptr(Py_buffer), lltype.Char], rffi.INT_real, error=CANNOT_FAIL)
+def PyBuffer_IsContiguous(space, view, fortran):
+    """Return 1 if the memory defined by the view is C-style (fortran is
+    'C') or Fortran-style (fortran is 'F') contiguous or either one
+    (fortran is 'A').  Return 0 otherwise."""
+    # PyPy only supports contiguous Py_buffers for now.
+    return space.wrap(1)
diff --git a/pypy/module/cpyext/bufferobject.py b/pypy/module/cpyext/bufferobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/bufferobject.py
@@ -0,0 +1,66 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import (
+    cpython_api, Py_ssize_t, cpython_struct, bootstrap_function,
+    PyObjectFields, PyObject)
+from pypy.module.cpyext.pyobject import make_typedescr, Py_DecRef
+from pypy.interpreter.buffer import Buffer, StringBuffer, SubBuffer
+
+
+PyBufferObjectStruct = lltype.ForwardReference()
+PyBufferObject = lltype.Ptr(PyBufferObjectStruct)
+PyBufferObjectFields = PyObjectFields + (
+    ("b_base", PyObject),
+    ("b_ptr", rffi.VOIDP),
+    ("b_size", Py_ssize_t),
+    ("b_offset", Py_ssize_t),
+    ("b_readonly", rffi.INT),
+    ("b_hash", rffi.LONG),
+    )
+
+cpython_struct("PyBufferObject", PyBufferObjectFields, PyBufferObjectStruct)
+
+ at bootstrap_function
+def init_bufferobject(space):
+    "Type description of PyBufferObject"
+    make_typedescr(space.gettypefor(Buffer).instancetypedef,
+                   basestruct=PyBufferObject.TO,
+                   attach=buffer_attach,
+                   dealloc=buffer_dealloc,
+                   realize=buffer_realize)
+
+def buffer_attach(space, py_obj, w_obj):
+    """
+    Fills a newly allocated PyBufferObject with the given (str) buffer object.
+    """
+    py_buf = rffi.cast(PyBufferObject, py_obj)
+    py_buf.c_b_offset = 0
+    rffi.setintfield(py_buf, 'c_b_readonly', 1)
+    rffi.setintfield(py_buf, 'c_b_hash', -1)
+
+    if isinstance(w_obj, SubBuffer):
+        py_buf.c_b_offset = w_obj.offset
+        w_obj = w_obj.buffer
+
+    if isinstance(w_obj, StringBuffer):
+        py_buf.c_b_base = rffi.cast(PyObject, 0) # space.wrap(w_obj.value)
+        py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, rffi.str2charp(w_obj.as_str()))
+        py_buf.c_b_size = w_obj.getlength()
+    else:
+        raise Exception("Fail fail fail fail fail")
+
+
+def buffer_realize(space, py_obj):
+    """
+    Creates the buffer in the PyPy interpreter from a cpyext representation.
+    """
+    raise Exception("realize fail fail fail")
+
+
+
+ at cpython_api([PyObject], lltype.Void, external=False)
+def buffer_dealloc(space, py_obj):
+    py_buf = rffi.cast(PyBufferObject, py_obj)
+    Py_DecRef(space, py_buf.c_b_base)
+    rffi.free_charp(rffi.cast(rffi.CCHARP, py_buf.c_b_ptr))
+    from pypy.module.cpyext.object import PyObject_dealloc
+    PyObject_dealloc(space, py_obj)
diff --git a/pypy/module/cpyext/include/bufferobject.h b/pypy/module/cpyext/include/bufferobject.h
--- a/pypy/module/cpyext/include/bufferobject.h
+++ b/pypy/module/cpyext/include/bufferobject.h
@@ -9,6 +9,17 @@
 extern "C" {
 #endif
 
+typedef struct {
+	PyObject_HEAD
+	PyObject *b_base;
+	void *b_ptr;
+	Py_ssize_t b_size;
+	Py_ssize_t b_offset;
+	int b_readonly;
+	long b_hash;
+} PyBufferObject;
+
+
 PyAPI_DATA(PyTypeObject) PyBuffer_Type;
 
 #define PyBuffer_Check(op) (((PyObject*)(op))->ob_type == &PyBuffer_Type)
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
@@ -234,7 +234,7 @@
 	writebufferproc bf_getwritebuffer;
 	segcountproc bf_getsegcount;
 	charbufferproc bf_getcharbuffer;
-  getbufferproc bf_getbuffer;
+	getbufferproc bf_getbuffer;
 	releasebufferproc bf_releasebuffer;
 } PyBufferProcs;
 
diff --git a/pypy/module/cpyext/src/bufferobject.c b/pypy/module/cpyext/src/bufferobject.c
--- a/pypy/module/cpyext/src/bufferobject.c
+++ b/pypy/module/cpyext/src/bufferobject.c
@@ -4,17 +4,6 @@
 #include "Python.h"
 
 
-typedef struct {
-	PyObject_HEAD
-	PyObject *b_base;
-	void *b_ptr;
-	Py_ssize_t b_size;
-	Py_ssize_t b_offset;
-	int b_readonly;
-	long b_hash;
-} PyBufferObject;
-
-
 enum buffer_t {
     READ_BUFFER,
     WRITE_BUFFER,
diff --git a/pypy/module/cpyext/src/getargs.c b/pypy/module/cpyext/src/getargs.c
--- a/pypy/module/cpyext/src/getargs.c
+++ b/pypy/module/cpyext/src/getargs.c
@@ -777,18 +777,14 @@
 			Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *);
 
 			if (PyString_Check(arg)) {
+                            fflush(stdout);
 				PyBuffer_FillInfo(p, arg,
 						  PyString_AS_STRING(arg), PyString_GET_SIZE(arg),
 						  1, 0);
-			} else {
-                            PyErr_SetString(
-                                PyExc_NotImplementedError,
-                                "s* not implemented for non-string values");
-                            return NULL;
-                        }
-#if 0
+			}
 #ifdef Py_USING_UNICODE
 			else if (PyUnicode_Check(arg)) {
+#if 0
 				uarg = UNICODE_DEFAULT_ENCODING(arg);
 				if (uarg == NULL)
 					return converterr(CONV_UNICODE,
@@ -796,6 +792,9 @@
 				PyBuffer_FillInfo(p, arg,
 						  PyString_AS_STRING(uarg), PyString_GET_SIZE(uarg),
 						  1, 0);
+#else
+                                return converterr("string or buffer", arg, msgbuf, bufsize);
+#endif
 			}
 #endif
 			else { /* any buffer-like object */
@@ -803,7 +802,6 @@
 				if (getbuffer(arg, p, &buf) < 0)
 					return converterr(buf, arg, msgbuf, bufsize);
 			}
-#endif
 			if (addcleanup(p, freelist, cleanup_buffer)) {
 				return converterr(
 					"(cleanup problem)",
@@ -1342,7 +1340,6 @@
 	return count;
 }
 
-#if 0 //YYY
 static int
 getbuffer(PyObject *arg, Py_buffer *view, char **errmsg)
 {
@@ -1373,7 +1370,6 @@
 	PyBuffer_FillInfo(view, NULL, buf, count, 1, 0);
 	return 0;
 }
-#endif
 
 /* Support for keyword arguments donated by
    Geoff Philbrick <philbric at delphi.hks.com> */
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
@@ -1,5 +1,5 @@
 from pypy.module.cpyext.api import (
-    cpython_api, PyObject, PyObjectP, CANNOT_FAIL
+    cpython_api, PyObject, PyObjectP, CANNOT_FAIL, Py_buffer
     )
 from pypy.module.cpyext.complexobject import Py_complex_ptr as Py_complex
 from pypy.rpython.lltypesystem import rffi, lltype
@@ -10,7 +10,6 @@
 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
@@ -178,13 +177,6 @@
     ~Py_buffer.format."""
     raise NotImplementedError
 
- at cpython_api([Py_buffer, lltype.Char], rffi.INT_real, error=CANNOT_FAIL)
-def PyBuffer_IsContiguous(space, view, fortran):
-    """Return 1 if the memory defined by the view is C-style (fortran is
-    'C') or Fortran-style (fortran is 'F') contiguous or either one
-    (fortran is 'A').  Return 0 otherwise."""
-    raise NotImplementedError
-
 @cpython_api([rffi.INT_real, Py_ssize_t, Py_ssize_t, Py_ssize_t, lltype.Char], lltype.Void)
 def PyBuffer_FillContiguousStrides(space, ndim, shape, strides, itemsize, fortran):
     """Fill the strides array with byte-strides of a contiguous (C-style if
diff --git a/pypy/module/cpyext/test/test_getargs.py b/pypy/module/cpyext/test/test_getargs.py
--- a/pypy/module/cpyext/test/test_getargs.py
+++ b/pypy/module/cpyext/test/test_getargs.py
@@ -129,6 +129,21 @@
         assert 'foo\0bar\0baz' == pybuffer('foo\0bar\0baz')
 
 
+    def test_pyarg_parse_string_old_buffer(self):
+        pybuffer = self.import_parser(
+            '''
+            Py_buffer buf;
+            PyObject *result;
+            if (!PyArg_ParseTuple(args, "s*", &buf)) {
+                return NULL;
+            }
+            result = PyString_FromStringAndSize(buf.buf, buf.len);
+            PyBuffer_Release(&buf);
+            return result;
+            ''')
+        assert 'foo\0bar\0baz' == pybuffer(buffer('foo\0bar\0baz'))
+
+
     def test_pyarg_parse_charbuf_and_length(self):
         """
         The `t#` format specifier can be used to parse a read-only 8-bit
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -28,6 +28,7 @@
     PyNumberMethods, PyMappingMethods, PySequenceMethods, PyBufferProcs)
 from pypy.module.cpyext.slotdefs import (
     slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
+from pypy.interpreter.buffer import Buffer
 from pypy.interpreter.error import OperationError
 from pypy.rlib.rstring import rsplit
 from pypy.rlib.objectmodel import specialize
@@ -418,8 +419,21 @@
     Py_DecRef(space, pyref)
     return space.len_w(w_str)
 
+ at cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
+             external=False, error=-1)
+def buf_getreadbuffer(space, pyref, segment, ref):
+    from pypy.module.cpyext.bufferobject import PyBufferObject
+    if segment != 0:
+        raise OperationError(space.w_SystemError, space.wrap
+                             ("accessing non-existent string segment"))
+    py_buf = rffi.cast(PyBufferObject, pyref)
+    ref[0] = py_buf.c_b_ptr
+    #Py_DecRef(space, pyref)
+    return py_buf.c_b_size
+
 def setup_string_buffer_procs(space, pto):
     c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
+    lltype.render_immortal(c_buf)
     c_buf.c_bf_getsegcount = llhelper(str_segcount.api_func.functype,
                                       str_segcount.api_func.get_wrapper(space))
     c_buf.c_bf_getreadbuffer = llhelper(str_getreadbuffer.api_func.functype,
@@ -429,6 +443,15 @@
     pto.c_tp_as_buffer = c_buf
     pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
 
+def setup_buffer_buffer_procs(space, pto):
+    c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
+    lltype.render_immortal(c_buf)
+    c_buf.c_bf_getsegcount = llhelper(str_segcount.api_func.functype,
+                                      str_segcount.api_func.get_wrapper(space))
+    c_buf.c_bf_getreadbuffer = llhelper(buf_getreadbuffer.api_func.functype,
+                                 buf_getreadbuffer.api_func.get_wrapper(space))
+    pto.c_tp_as_buffer = c_buf
+
 @cpython_api([PyObject], lltype.Void, external=False)
 def type_dealloc(space, obj):
     from pypy.module.cpyext.object import PyObject_dealloc
@@ -484,6 +507,8 @@
     # buffer protocol
     if space.is_w(w_type, space.w_str):
         setup_string_buffer_procs(space, pto)
+    if space.is_w(w_type, space.gettypefor(Buffer)):
+        setup_buffer_buffer_procs(space, pto)
 
     pto.c_tp_free = llhelper(PyObject_Del.api_func.functype,
             PyObject_Del.api_func.get_wrapper(space))


More information about the pypy-commit mailing list