[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