Author: Amaury Forgeot d'Arc <amaur...@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) + +@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) + +@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") + + + +@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 <philb...@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 -@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) +@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)) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit