[pypy-commit] pypy py3k: cpyext: add support for the new buffer interface.

amauryfa noreply at buildbot.pypy.org
Fri Sep 21 23:53:36 CEST 2012


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3k
Changeset: r57468:4cbe89f3cec7
Date: 2012-09-21 23:52 +0200
http://bitbucket.org/pypy/pypy/changeset/4cbe89f3cec7/

Log:	cpyext: add support for the new buffer interface. Most of the tests
	pass now...

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,7 +45,6 @@
 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
@@ -186,6 +186,9 @@
         self.argnames = argnames[1:]
         assert len(self.argnames) == len(self.argtypes)
 
+    def __repr__(self):
+        return "<cpyext function %s>" % (self.callable.__name__,)
+
     def _freeze_(self):
         return True
 
@@ -358,8 +361,7 @@
     'PyEval_CallFunction', 'PyEval_CallMethod', 'PyObject_CallFunction',
     'PyObject_CallMethod', 'PyObject_CallFunctionObjArgs', 'PyObject_CallMethodObjArgs',
 
-    'PyBuffer_FromMemory', 'PyBuffer_FromReadWriteMemory', 'PyBuffer_FromObject',
-    'PyBuffer_FromReadWriteObject', 'PyBuffer_New', 'PyBuffer_Type', 'init_bufferobject',
+    'PyObject_GetBuffer', 'PyBuffer_Release',
 
     'PyCObject_FromVoidPtr', 'PyCObject_FromVoidPtrAndDesc', 'PyCObject_AsVoidPtr',
     'PyCObject_GetDesc', 'PyCObject_Import', 'PyCObject_SetVoidPtr',
@@ -633,11 +635,9 @@
         globals()['va_get_%s' % name_no_star] = func
 
 def setup_init_functions(eci):
-    init_buffer = rffi.llexternal('init_bufferobject', [], lltype.Void, compilation_info=eci)
     init_pycobject = rffi.llexternal('init_pycobject', [], lltype.Void, compilation_info=eci)
     init_capsule = rffi.llexternal('init_capsule', [], lltype.Void, compilation_info=eci)
     INIT_FUNCTIONS.extend([
-        lambda space: init_buffer(),
         lambda space: init_pycobject(),
         lambda space: init_capsule(),
     ])
@@ -954,7 +954,6 @@
                                source_dir / "mysnprintf.c",
                                source_dir / "pythonrun.c",
                                source_dir / "sysmodule.c",
-                               source_dir / "bufferobject.c",
                                source_dir / "cobject.c",
                                source_dir / "structseq.c",
                                source_dir / "capsule.c",
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
--- a/pypy/module/cpyext/buffer.py
+++ b/pypy/module/cpyext/buffer.py
@@ -4,38 +4,10 @@
     cpython_api, CANNOT_FAIL, Py_buffer)
 from pypy.module.cpyext.pyobject import PyObject
 
- at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
-def PyObject_CheckBuffer(space, w_obj):
-    """Return 1 if obj supports the buffer interface otherwise 0."""
-    return 0  # the bf_getbuffer field is never filled by cpyext
-
- at cpython_api([PyObject, lltype.Ptr(Py_buffer), 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
-    never be NULL.  The flags argument is a bit field indicating what
-    kind of buffer the caller is prepared to deal with and therefore what
-    kind of buffer the exporter is allowed to return.  The buffer interface
-    allows for complicated memory sharing possibilities, but some caller may
-    not be able to handle all the complexity but may want to see if the
-    exporter will let them take a simpler view to its memory.
-
-    Some exporters may not be able to share memory in every possible way and
-    may need to raise errors to signal to some consumers that something is
-    just not possible. These errors should be a BufferError unless
-    there is another error that is actually causing the problem. The
-    exporter can use flags information to simplify how much of the
-    Py_buffer structure is filled in with non-default values and/or
-    raise an error if the object can't support a simpler view of its memory.
-
-    0 is returned on success and -1 on error."""
-    raise OperationError(space.w_TypeError, space.wrap(
-            'PyPy does not yet implement the new buffer interface'))
-
 @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)
+    return 1
diff --git a/pypy/module/cpyext/bufferobject.py b/pypy/module/cpyext/bufferobject.py
deleted file mode 100644
--- a/pypy/module/cpyext/bufferobject.py
+++ /dev/null
@@ -1,80 +0,0 @@
-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, make_ref
-from pypy.interpreter.buffer import Buffer, StringBuffer, SubBuffer
-from pypy.interpreter.error import OperationError
-from pypy.module.array.interp_array import ArrayBuffer
-
-
-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 w_obj already allocated a fixed buffer, use it, and keep a
-    # reference to w_obj.
-    # Otherwise, b_base stays NULL, and we own the b_ptr.
-
-    if isinstance(w_obj, StringBuffer):
-        py_buf.c_b_base = lltype.nullptr(PyObject.TO)
-        py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, rffi.str2charp(w_obj.value))
-        py_buf.c_b_size = w_obj.getlength()
-    elif isinstance(w_obj, ArrayBuffer):
-        w_base = w_obj.array
-        py_buf.c_b_base = make_ref(space, w_base)
-        py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, w_obj.array._charbuf_start())
-        py_buf.c_b_size = w_obj.getlength()
-    else:
-        raise OperationError(space.w_NotImplementedError, space.wrap(
-            "buffer flavor not supported"))
-
-
-def buffer_realize(space, py_obj):
-    """
-    Creates the buffer in the PyPy interpreter from a cpyext representation.
-    """
-    raise OperationError(space.w_NotImplementedError, space.wrap(
-        "Don't know how to realize a buffer"))
-
-
- at cpython_api([PyObject], lltype.Void, external=False)
-def buffer_dealloc(space, py_obj):
-    py_buf = rffi.cast(PyBufferObject, py_obj)
-    if py_buf.c_b_base:
-        Py_DecRef(space, py_buf.c_b_base)
-    else:
-        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/Python.h b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -83,6 +83,7 @@
 #include "pyconfig.h"
 
 #include "object.h"
+#include "abstract.h"
 #include "pyport.h"
 #include "warnings.h"
 
@@ -117,7 +118,6 @@
 #include "pymem.h"
 #include "pycobject.h"
 #include "pycapsule.h"
-#include "bufferobject.h"
 #include "bytesobject.h"
 #include "sliceobject.h"
 #include "datetime.h"
diff --git a/pypy/module/cpyext/include/abstract.h b/pypy/module/cpyext/include/abstract.h
--- a/pypy/module/cpyext/include/abstract.h
+++ b/pypy/module/cpyext/include/abstract.h
@@ -1,1 +1,28 @@
-/* empty */
+#ifndef Py_ABSTRACTOBJECT_H
+#define Py_ABSTRACTOBJECT_H
+
+    /* new buffer API */
+
+#define PyObject_CheckBuffer(obj) \
+    (((obj)->ob_type->tp_as_buffer != NULL) &&  \
+     ((obj)->ob_type->tp_as_buffer->bf_getbuffer != NULL))
+
+    /* Return 1 if the getbuffer function is available, otherwise
+       return 0 */
+
+     PyAPI_FUNC(int) PyObject_GetBuffer(PyObject *obj, Py_buffer *view,
+                                        int flags);
+
+    /* This is a C-API version of the getbuffer function call.  It checks
+       to make sure object has the required function pointer and issues the
+       call.  Returns -1 and raises an error on failure and returns 0 on
+       success
+    */
+
+
+     PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view);
+
+    /* Releases a Py_buffer obtained from getbuffer ParseTuple's s*.
+    */
+
+#endif /* Py_ABSTRACTOBJECT_H */
diff --git a/pypy/module/cpyext/include/bufferobject.h b/pypy/module/cpyext/include/bufferobject.h
deleted file mode 100644
--- a/pypy/module/cpyext/include/bufferobject.h
+++ /dev/null
@@ -1,45 +0,0 @@
-
-/* Buffer object interface */
-
-/* Note: the object's structure is private */
-
-#ifndef Py_BUFFEROBJECT_H
-#define Py_BUFFEROBJECT_H
-#ifdef __cplusplus
-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)
-
-#define Py_END_OF_BUFFER	(-1)
-
-PyObject* PyBuffer_FromObject(PyObject *base,
-                                           Py_ssize_t offset, Py_ssize_t size);
-PyObject* PyBuffer_FromReadWriteObject(PyObject *base,
-                                                    Py_ssize_t offset,
-                                                    Py_ssize_t size);
-
-PyObject* PyBuffer_FromMemory(void *ptr, Py_ssize_t size);
-PyObject* PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size);
-
-PyObject* PyBuffer_New(Py_ssize_t size);
-
-void init_bufferobject(void);
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* !Py_BUFFEROBJECT_H */
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
@@ -125,17 +125,6 @@
 typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *);
 
 
-/* int-based buffer interface */
-typedef int (*getreadbufferproc)(PyObject *, int, void **);
-typedef int (*getwritebufferproc)(PyObject *, int, void **);
-typedef int (*getsegcountproc)(PyObject *, int *);
-typedef int (*getcharbufferproc)(PyObject *, int, char **);
-/* ssize_t-based buffer interface */
-typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **);
-typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **);
-typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *);
-typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **);
-
 /* Py3k buffer interface */
 typedef struct bufferinfo {
     void *buf;
@@ -274,12 +263,8 @@
 } PyMappingMethods;
 
 typedef struct {
-	readbufferproc bf_getreadbuffer;
-	writebufferproc bf_getwritebuffer;
-	segcountproc bf_getsegcount;
-	charbufferproc bf_getcharbuffer;
-	getbufferproc bf_getbuffer;
-	releasebufferproc bf_releasebuffer;
+     getbufferproc bf_getbuffer;
+     releasebufferproc bf_releasebuffer;
 } PyBufferProcs;
 
 
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -471,15 +471,3 @@
     view.c_internal = lltype.nullptr(rffi.VOIDP.TO)
 
     return 0
-
-
- at cpython_api([lltype.Ptr(Py_buffer)], lltype.Void, error=CANNOT_FAIL)
-def PyBuffer_Release(space, view):
-    """
-    Releases a Py_buffer obtained from getbuffer ParseTuple's s*.
-
-    This is not a complete re-implementation of the CPython API; it only
-    provides a subset of CPython's behavior.
-    """
-    Py_DecRef(space, view.c_obj)
-    view.c_obj = lltype.nullptr(PyObject.TO)
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
@@ -4,13 +4,13 @@
 
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
-    cpython_api, generic_cpy_call, PyObject, Py_ssize_t)
+    cpython_api, generic_cpy_call, PyObject, Py_ssize_t, Py_buffer)
 from pypy.module.cpyext.typeobjectdefs import (
     unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc,
     getattrfunc, getattrofunc, setattrofunc, lenfunc, ssizeargfunc, inquiry,
     ssizessizeargfunc, ssizeobjargproc, iternextfunc, initproc, richcmpfunc,
     cmpfunc, hashfunc, descrgetfunc, descrsetfunc, objobjproc, objobjargproc,
-    readbufferproc)
+    getbufferproc, releasebufferproc)
 from pypy.module.cpyext.pyobject import from_ref
 from pypy.module.cpyext.pyerrors import PyErr_Occurred
 from pypy.module.cpyext.state import State
@@ -242,14 +242,15 @@
     def getitem(self, index):
         return self.ptr[index]
 
-def wrap_getreadbuffer(space, w_self, w_args, func):
-    func_target = rffi.cast(readbufferproc, func)
-    with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as ptr:
-        index = rffi.cast(Py_ssize_t, 0)
-        size = generic_cpy_call(space, func_target, w_self, index, ptr)
-        if size < 0:
+def wrap_getbuffer(space, w_self, w_args, func):
+    func_target = rffi.cast(getbufferproc, func)
+    with lltype.scoped_alloc(Py_buffer) as view:
+        flags = rffi.cast(rffi.INT_real, 0)
+        print "AFA CALL GETBUFFER"
+        ret = generic_cpy_call(space, func_target, w_self, view, flags)
+        if ret < 0:
             space.fromcache(State).check_and_raise_exception(always=True)
-        return space.wrap(CPyBuffer(ptr[0], size, w_self))
+        return space.wrap(CPyBuffer(view.c_buf, view.c_len, w_self))
 
 def get_richcmp_func(OP_CONST):
     def inner(space, w_self, w_args, func):
@@ -643,7 +644,7 @@
 slotdefs = eval(slotdefs_str)
 # PyPy addition
 slotdefs += (
-    TPSLOT("__buffer__", "tp_as_buffer.c_bf_getreadbuffer", None, "wrap_getreadbuffer", ""),
+    TPSLOT("__buffer__", "tp_as_buffer.c_bf_getbuffer", None, "wrap_getbuffer", ""),
 )
 
 # partial sort to solve some slot conflicts:
diff --git a/pypy/module/cpyext/src/abstract.c b/pypy/module/cpyext/src/abstract.c
--- a/pypy/module/cpyext/src/abstract.c
+++ b/pypy/module/cpyext/src/abstract.c
@@ -26,12 +26,16 @@
 PyObject_CheckReadBuffer(PyObject *obj)
 {
     PyBufferProcs *pb = obj->ob_type->tp_as_buffer;
+    Py_buffer view;
 
     if (pb == NULL ||
-        pb->bf_getreadbuffer == NULL ||
-        pb->bf_getsegcount == NULL ||
-        (*pb->bf_getsegcount)(obj, NULL) != 1)
+        pb->bf_getbuffer == NULL)
         return 0;
+    if ((*pb->bf_getbuffer)(obj, &view, PyBUF_SIMPLE) == -1) {
+        PyErr_Clear();
+        return 0;
+    }
+    PyBuffer_Release(&view);
     return 1;
 }
 
@@ -40,8 +44,7 @@
                           Py_ssize_t *buffer_len)
 {
     PyBufferProcs *pb;
-    void *pp;
-    Py_ssize_t len;
+    Py_buffer view;
 
     if (obj == NULL || buffer == NULL || buffer_len == NULL) {
         null_error();
@@ -49,22 +52,19 @@
     }
     pb = obj->ob_type->tp_as_buffer;
     if (pb == NULL ||
-         pb->bf_getreadbuffer == NULL ||
-         pb->bf_getsegcount == NULL) {
+        pb->bf_getbuffer == NULL) {
         PyErr_SetString(PyExc_TypeError,
-                        "expected a readable buffer object");
+                        "expected an object with a buffer interface");
         return -1;
     }
-    if ((*pb->bf_getsegcount)(obj, NULL) != 1) {
-        PyErr_SetString(PyExc_TypeError,
-                        "expected a single-segment buffer object");
-        return -1;
-    }
-    len = (*pb->bf_getreadbuffer)(obj, 0, &pp);
-    if (len < 0)
-        return -1;
-    *buffer = pp;
-    *buffer_len = len;
+
+    if ((*pb->bf_getbuffer)(obj, &view, PyBUF_SIMPLE)) return -1;
+
+    *buffer = view.buf;
+    *buffer_len = view.len;
+    if (pb->bf_releasebuffer != NULL)
+        (*pb->bf_releasebuffer)(obj, &view);
+    Py_XDECREF(view.obj);
     return 0;
 }
 
@@ -73,8 +73,7 @@
                            Py_ssize_t *buffer_len)
 {
     PyBufferProcs *pb;
-    void*pp;
-    Py_ssize_t len;
+    Py_buffer view;
 
     if (obj == NULL || buffer == NULL || buffer_len == NULL) {
         null_error();
@@ -82,23 +81,43 @@
     }
     pb = obj->ob_type->tp_as_buffer;
     if (pb == NULL ||
-         pb->bf_getwritebuffer == NULL ||
-         pb->bf_getsegcount == NULL) {
+        pb->bf_getbuffer == NULL ||
+        ((*pb->bf_getbuffer)(obj, &view, PyBUF_WRITABLE) != 0)) {
         PyErr_SetString(PyExc_TypeError,
-                        "expected a writeable buffer object");
+                        "expected an object with a writable buffer interface");
         return -1;
     }
-    if ((*pb->bf_getsegcount)(obj, NULL) != 1) {
-        PyErr_SetString(PyExc_TypeError,
-                        "expected a single-segment buffer object");
+
+    *buffer = view.buf;
+    *buffer_len = view.len;
+    if (pb->bf_releasebuffer != NULL)
+        (*pb->bf_releasebuffer)(obj, &view);
+    Py_XDECREF(view.obj);
+    return 0;
+}
+
+/* Buffer C-API for Python 3.0 */
+
+int
+PyObject_GetBuffer(PyObject *obj, Py_buffer *view, int flags)
+{
+    if (!PyObject_CheckBuffer(obj)) {
+        PyErr_Format(PyExc_TypeError,
+                     "'%100s' does not support the buffer interface",
+                     Py_TYPE(obj)->tp_name);
         return -1;
     }
-    len = (*pb->bf_getwritebuffer)(obj,0,&pp);
-    if (len < 0)
-        return -1;
-    *buffer = pp;
-    *buffer_len = len;
-    return 0;
+    return (*(obj->ob_type->tp_as_buffer->bf_getbuffer))(obj, view, flags);
+}
+
+void
+PyBuffer_Release(Py_buffer *view)
+{
+    PyObject *obj = view->obj;
+    if (obj && Py_TYPE(obj)->tp_as_buffer && Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer)
+        Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer(obj, view);
+    Py_XDECREF(obj);
+    view->obj = NULL;
 }
 
 /* Operations on callable objects */
diff --git a/pypy/module/cpyext/src/bufferobject.c b/pypy/module/cpyext/src/bufferobject.c
deleted file mode 100644
--- a/pypy/module/cpyext/src/bufferobject.c
+++ /dev/null
@@ -1,853 +0,0 @@
-
-/* Buffer object implementation */
-
-#include "Python.h"
-
-
-enum buffer_t {
-    READ_BUFFER,
-    WRITE_BUFFER,
-    CHAR_BUFFER,
-    ANY_BUFFER
-};
-
-static int
-get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size,
-    enum buffer_t buffer_type)
-{
-    if (self->b_base == NULL) {
-        assert (ptr != NULL);
-        *ptr = self->b_ptr;
-        *size = self->b_size;
-    }
-    else {
-        Py_ssize_t count, offset;
-        readbufferproc proc = 0;
-        PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer;
-        if ((*bp->bf_getsegcount)(self->b_base, NULL) != 1) {
-            PyErr_SetString(PyExc_TypeError,
-                "single-segment buffer object expected");
-            return 0;
-        }
-        if ((buffer_type == READ_BUFFER) ||
-            ((buffer_type == ANY_BUFFER) && self->b_readonly))
-            proc = bp->bf_getreadbuffer;
-        else if ((buffer_type == WRITE_BUFFER) ||
-            (buffer_type == ANY_BUFFER))
-	    proc = (readbufferproc)bp->bf_getwritebuffer;
-        else if (buffer_type == CHAR_BUFFER) {
-            if (!PyType_HasFeature(self->ob_type,
-                        Py_TPFLAGS_HAVE_GETCHARBUFFER)) {
-            PyErr_SetString(PyExc_TypeError,
-                "Py_TPFLAGS_HAVE_GETCHARBUFFER needed");
-            return 0;
-            }
-            proc = (readbufferproc)bp->bf_getcharbuffer;
-        }
-        if (!proc) {
-            char *buffer_type_name;
-            switch (buffer_type) {
-            case READ_BUFFER:
-                buffer_type_name = "read";
-                break;
-            case WRITE_BUFFER:
-                buffer_type_name = "write";
-                break;
-            case CHAR_BUFFER:
-                buffer_type_name = "char";
-                break;
-            default:
-                buffer_type_name = "no";
-                break;
-            }
-            PyErr_Format(PyExc_TypeError,
-                "%s buffer type not available",
-                buffer_type_name);
-            return 0;
-        }
-        if ((count = (*proc)(self->b_base, 0, ptr)) < 0)
-            return 0;
-        /* apply constraints to the start/end */
-        if (self->b_offset > count)
-            offset = count;
-        else
-            offset = self->b_offset;
-        *(char **)ptr = *(char **)ptr + offset;
-        if (self->b_size == Py_END_OF_BUFFER)
-            *size = count;
-        else
-            *size = self->b_size;
-        if (offset + *size > count)
-            *size = count - offset;
-    }
-    return 1;
-}
-
-
-static PyObject *
-buffer_from_memory(PyObject *base, Py_ssize_t size, Py_ssize_t offset, void *ptr,
-                   int readonly)
-{
-    PyBufferObject * b;
-
-    if (size < 0 && size != Py_END_OF_BUFFER) {
-        PyErr_SetString(PyExc_ValueError,
-                        "size must be zero or positive");
-        return NULL;
-    }
-    if (offset < 0) {
-        PyErr_SetString(PyExc_ValueError,
-                        "offset must be zero or positive");
-        return NULL;
-    }
-
-    b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
-    if ( b == NULL )
-        return NULL;
-
-    Py_XINCREF(base);
-    b->b_base = base;
-    b->b_ptr = ptr;
-    b->b_size = size;
-    b->b_offset = offset;
-    b->b_readonly = readonly;
-    b->b_hash = -1;
-
-    return (PyObject *) b;
-}
-
-static PyObject *
-buffer_from_object(PyObject *base, Py_ssize_t size, Py_ssize_t offset, int readonly)
-{
-    if (offset < 0) {
-        PyErr_SetString(PyExc_ValueError,
-                        "offset must be zero or positive");
-        return NULL;
-    }
-    if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) ) {
-        /* another buffer, refer to the base object */
-        PyBufferObject *b = (PyBufferObject *)base;
-        if (b->b_size != Py_END_OF_BUFFER) {
-            Py_ssize_t base_size = b->b_size - offset;
-            if (base_size < 0)
-                base_size = 0;
-            if (size == Py_END_OF_BUFFER || size > base_size)
-                size = base_size;
-        }
-        offset += b->b_offset;
-        base = b->b_base;
-    }
-    return buffer_from_memory(base, size, offset, NULL, readonly);
-}
-
-
-PyObject *
-PyBuffer_FromObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
-{
-    PyBufferProcs *pb = base->ob_type->tp_as_buffer;
-
-    if ( pb == NULL ||
-         pb->bf_getreadbuffer == NULL ||
-         pb->bf_getsegcount == NULL )
-    {
-        PyErr_SetString(PyExc_TypeError, "buffer object expected");
-        return NULL;
-    }
-
-    return buffer_from_object(base, size, offset, 1);
-}
-
-PyObject *
-PyBuffer_FromReadWriteObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
-{
-    PyBufferProcs *pb = base->ob_type->tp_as_buffer;
-
-    if ( pb == NULL ||
-         pb->bf_getwritebuffer == NULL ||
-         pb->bf_getsegcount == NULL )
-    {
-        PyErr_SetString(PyExc_TypeError, "buffer object expected");
-        return NULL;
-    }
-
-    return buffer_from_object(base, size,  offset, 0);
-}
-
-PyObject *
-PyBuffer_FromMemory(void *ptr, Py_ssize_t size)
-{
-    return buffer_from_memory(NULL, size, 0, ptr, 1);
-}
-
-PyObject *
-PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size)
-{
-    return buffer_from_memory(NULL, size, 0, ptr, 0);
-}
-
-PyObject *
-PyBuffer_New(Py_ssize_t size)
-{
-    PyObject *o;
-    PyBufferObject * b;
-
-    if (size < 0) {
-        PyErr_SetString(PyExc_ValueError,
-                        "size must be zero or positive");
-        return NULL;
-    }
-    if (sizeof(*b) > PY_SSIZE_T_MAX - size) {
-        /* unlikely */
-        return PyErr_NoMemory();
-    }
-    /* Inline PyObject_New */
-    o = (PyObject *)PyObject_MALLOC(sizeof(*b) + size);
-    if ( o == NULL )
-        return PyErr_NoMemory();
-    b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type);
-
-    b->b_base = NULL;
-    b->b_ptr = (void *)(b + 1);
-    b->b_size = size;
-    b->b_offset = 0;
-    b->b_readonly = 0;
-    b->b_hash = -1;
-
-    return o;
-}
-
-/* Methods */
-
-static PyObject *
-buffer_new(PyTypeObject *type, PyObject *args, PyObject *kw)
-{
-    PyObject *ob;
-    Py_ssize_t offset = 0;
-    Py_ssize_t size = Py_END_OF_BUFFER;
-
-    /*
-     * if (PyErr_WarnPy3k("buffer() not supported in 3.x", 1) < 0)
-     *   return NULL;
-     */
-
-    if (!_PyArg_NoKeywords("buffer()", kw))
-        return NULL;
-
-    if (!PyArg_ParseTuple(args, "O|nn:buffer", &ob, &offset, &size))
-        return NULL;
-    return PyBuffer_FromObject(ob, offset, size);
-}
-
-PyDoc_STRVAR(buffer_doc,
-"buffer(object [, offset[, size]])\n\
-\n\
-Create a new buffer object which references the given object.\n\
-The buffer will reference a slice of the target object from the\n\
-start of the object (or at the specified offset). The slice will\n\
-extend to the end of the target object (or with the specified size).");
-
-
-static void
-buffer_dealloc(PyBufferObject *self)
-{
-    Py_XDECREF(self->b_base);
-    PyObject_DEL(self);
-}
-
-static int
-buffer_compare(PyBufferObject *self, PyBufferObject *other)
-{
-    void *p1, *p2;
-    Py_ssize_t len_self, len_other, min_len;
-    int cmp;
-
-    if (!get_buf(self, &p1, &len_self, ANY_BUFFER))
-        return -1;
-    if (!get_buf(other, &p2, &len_other, ANY_BUFFER))
-        return -1;
-    min_len = (len_self < len_other) ? len_self : len_other;
-    if (min_len > 0) {
-        cmp = memcmp(p1, p2, min_len);
-        if (cmp != 0)
-            return cmp < 0 ? -1 : 1;
-    }
-    return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
-}
-
-static PyObject *
-buffer_repr(PyBufferObject *self)
-{
-    const char *status = self->b_readonly ? "read-only" : "read-write";
-
-    if ( self->b_base == NULL )
-        return PyUnicode_FromFormat("<%s buffer ptr %p, size %zd at %p>",
-                                   status,
-                                   self->b_ptr,
-                                   self->b_size,
-                                   self);
-    else
-        return PyUnicode_FromFormat(
-            "<%s buffer for %p, size %zd, offset %zd at %p>",
-            status,
-            self->b_base,
-            self->b_size,
-            self->b_offset,
-            self);
-}
-
-static long
-buffer_hash(PyBufferObject *self)
-{
-    void *ptr;
-    Py_ssize_t size;
-    register Py_ssize_t len;
-    register unsigned char *p;
-    register long x;
-
-    if ( self->b_hash != -1 )
-        return self->b_hash;
-
-    /* XXX potential bugs here, a readonly buffer does not imply that the
-     * underlying memory is immutable.  b_readonly is a necessary but not
-     * sufficient condition for a buffer to be hashable.  Perhaps it would
-     * be better to only allow hashing if the underlying object is known to
-     * be immutable (e.g. PyString_Check() is true).  Another idea would
-     * be to call tp_hash on the underlying object and see if it raises
-     * an error. */
-    if ( !self->b_readonly )
-    {
-        PyErr_SetString(PyExc_TypeError,
-                        "writable buffers are not hashable");
-        return -1;
-    }
-
-    if (!get_buf(self, &ptr, &size, ANY_BUFFER))
-        return -1;
-    p = (unsigned char *) ptr;
-    len = size;
-    x = *p << 7;
-    while (--len >= 0)
-        x = (1000003*x) ^ *p++;
-    x ^= size;
-    if (x == -1)
-        x = -2;
-    self->b_hash = x;
-    return x;
-}
-
-static PyObject *
-buffer_str(PyBufferObject *self)
-{
-    void *ptr;
-    Py_ssize_t size;
-    if (!get_buf(self, &ptr, &size, ANY_BUFFER))
-        return NULL;
-    return PyString_FromStringAndSize((const char *)ptr, size);
-}
-
-/* Sequence methods */
-
-static Py_ssize_t
-buffer_length(PyBufferObject *self)
-{
-    void *ptr;
-    Py_ssize_t size;
-    if (!get_buf(self, &ptr, &size, ANY_BUFFER))
-        return -1;
-    return size;
-}
-
-static PyObject *
-buffer_concat(PyBufferObject *self, PyObject *other)
-{
-    PyBufferProcs *pb = other->ob_type->tp_as_buffer;
-    void *ptr1, *ptr2;
-    char *p;
-    PyObject *ob;
-    Py_ssize_t size, count;
-
-    if ( pb == NULL ||
-         pb->bf_getreadbuffer == NULL ||
-         pb->bf_getsegcount == NULL )
-    {
-        PyErr_BadArgument();
-        return NULL;
-    }
-    if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
-    {
-        /* ### use a different exception type/message? */
-        PyErr_SetString(PyExc_TypeError,
-                        "single-segment buffer object expected");
-        return NULL;
-    }
-
-    if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
-        return NULL;
-
-    /* optimize special case */
-    if ( size == 0 )
-    {
-        Py_INCREF(other);
-        return other;
-    }
-
-    if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
-        return NULL;
-
-    assert(count <= PY_SIZE_MAX - size);
-
-    ob = PyString_FromStringAndSize(NULL, size + count);
-    if ( ob == NULL )
-        return NULL;
-    p = PyString_AS_STRING(ob);
-    memcpy(p, ptr1, size);
-    memcpy(p + size, ptr2, count);
-
-    /* there is an extra byte in the string object, so this is safe */
-    p[size + count] = '\0';
-
-    return ob;
-}
-
-static PyObject *
-buffer_repeat(PyBufferObject *self, Py_ssize_t count)
-{
-    PyObject *ob;
-    register char *p;
-    void *ptr;
-    Py_ssize_t size;
-
-    if ( count < 0 )
-        count = 0;
-    if (!get_buf(self, &ptr, &size, ANY_BUFFER))
-        return NULL;
-    if (count > PY_SSIZE_T_MAX / size) {
-        PyErr_SetString(PyExc_MemoryError, "result too large");
-        return NULL;
-    }
-    ob = PyString_FromStringAndSize(NULL, size * count);
-    if ( ob == NULL )
-        return NULL;
-
-    p = PyString_AS_STRING(ob);
-    while ( count-- )
-    {
-        memcpy(p, ptr, size);
-        p += size;
-    }
-
-    /* there is an extra byte in the string object, so this is safe */
-    *p = '\0';
-
-    return ob;
-}
-
-static PyObject *
-buffer_item(PyBufferObject *self, Py_ssize_t idx)
-{
-    void *ptr;
-    Py_ssize_t size;
-    if (!get_buf(self, &ptr, &size, ANY_BUFFER))
-        return NULL;
-    if ( idx < 0 || idx >= size ) {
-        PyErr_SetString(PyExc_IndexError, "buffer index out of range");
-        return NULL;
-    }
-    return PyString_FromStringAndSize((char *)ptr + idx, 1);
-}
-
-static PyObject *
-buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
-{
-    void *ptr;
-    Py_ssize_t size;
-    if (!get_buf(self, &ptr, &size, ANY_BUFFER))
-        return NULL;
-    if ( left < 0 )
-        left = 0;
-    if ( right < 0 )
-        right = 0;
-    if ( right > size )
-        right = size;
-    if ( right < left )
-        right = left;
-    return PyString_FromStringAndSize((char *)ptr + left,
-                                      right - left);
-}
-
-static PyObject *
-buffer_subscript(PyBufferObject *self, PyObject *item)
-{
-    void *p;
-    Py_ssize_t size;
-
-    if (!get_buf(self, &p, &size, ANY_BUFFER))
-        return NULL;
-    if (PyIndex_Check(item)) {
-        Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
-        if (i == -1 && PyErr_Occurred())
-            return NULL;
-        if (i < 0)
-            i += size;
-        return buffer_item(self, i);
-    }
-    else if (PySlice_Check(item)) {
-        Py_ssize_t start, stop, step, slicelength, cur, i;
-
-        if (PySlice_GetIndicesEx((PySliceObject*)item, size,
-                         &start, &stop, &step, &slicelength) < 0) {
-            return NULL;
-        }
-
-        if (slicelength <= 0)
-            return PyString_FromStringAndSize("", 0);
-        else if (step == 1)
-            return PyString_FromStringAndSize((char *)p + start,
-                                              stop - start);
-        else {
-            PyObject *result;
-            char *source_buf = (char *)p;
-            char *result_buf = (char *)PyMem_Malloc(slicelength);
-
-            if (result_buf == NULL)
-                return PyErr_NoMemory();
-
-            for (cur = start, i = 0; i < slicelength;
-                 cur += step, i++) {
-                result_buf[i] = source_buf[cur];
-            }
-
-            result = PyString_FromStringAndSize(result_buf,
-                                                slicelength);
-            PyMem_Free(result_buf);
-            return result;
-        }
-    }
-    else {
-        PyErr_SetString(PyExc_TypeError,
-                        "sequence index must be integer");
-        return NULL;
-    }
-}
-
-static int
-buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
-{
-    PyBufferProcs *pb;
-    void *ptr1, *ptr2;
-    Py_ssize_t size;
-    Py_ssize_t count;
-
-    if ( self->b_readonly ) {
-        PyErr_SetString(PyExc_TypeError,
-                        "buffer is read-only");
-        return -1;
-    }
-
-    if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
-        return -1;
-
-    if (idx < 0 || idx >= size) {
-        PyErr_SetString(PyExc_IndexError,
-                        "buffer assignment index out of range");
-        return -1;
-    }
-
-    pb = other ? other->ob_type->tp_as_buffer : NULL;
-    if ( pb == NULL ||
-         pb->bf_getreadbuffer == NULL ||
-         pb->bf_getsegcount == NULL )
-    {
-        PyErr_BadArgument();
-        return -1;
-    }
-    if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
-    {
-        /* ### use a different exception type/message? */
-        PyErr_SetString(PyExc_TypeError,
-                        "single-segment buffer object expected");
-        return -1;
-    }
-
-    if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
-        return -1;
-    if ( count != 1 ) {
-        PyErr_SetString(PyExc_TypeError,
-                        "right operand must be a single byte");
-        return -1;
-    }
-
-    ((char *)ptr1)[idx] = *(char *)ptr2;
-    return 0;
-}
-
-static int
-buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObject *other)
-{
-    PyBufferProcs *pb;
-    void *ptr1, *ptr2;
-    Py_ssize_t size;
-    Py_ssize_t slice_len;
-    Py_ssize_t count;
-
-    if ( self->b_readonly ) {
-        PyErr_SetString(PyExc_TypeError,
-                        "buffer is read-only");
-        return -1;
-    }
-
-    pb = other ? other->ob_type->tp_as_buffer : NULL;
-    if ( pb == NULL ||
-         pb->bf_getreadbuffer == NULL ||
-         pb->bf_getsegcount == NULL )
-    {
-        PyErr_BadArgument();
-        return -1;
-    }
-    if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
-    {
-        /* ### use a different exception type/message? */
-        PyErr_SetString(PyExc_TypeError,
-                        "single-segment buffer object expected");
-        return -1;
-    }
-    if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
-        return -1;
-    if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
-        return -1;
-
-    if ( left < 0 )
-        left = 0;
-    else if ( left > size )
-        left = size;
-    if ( right < left )
-        right = left;
-    else if ( right > size )
-        right = size;
-    slice_len = right - left;
-
-    if ( count != slice_len ) {
-        PyErr_SetString(
-            PyExc_TypeError,
-            "right operand length must match slice length");
-        return -1;
-    }
-
-    if ( slice_len )
-        memcpy((char *)ptr1 + left, ptr2, slice_len);
-
-    return 0;
-}
-
-static int
-buffer_ass_subscript(PyBufferObject *self, PyObject *item, PyObject *value)
-{
-    PyBufferProcs *pb;
-    void *ptr1, *ptr2;
-    Py_ssize_t selfsize;
-    Py_ssize_t othersize;
-
-    if ( self->b_readonly ) {
-        PyErr_SetString(PyExc_TypeError,
-                        "buffer is read-only");
-        return -1;
-    }
-
-    pb = value ? value->ob_type->tp_as_buffer : NULL;
-    if ( pb == NULL ||
-         pb->bf_getreadbuffer == NULL ||
-         pb->bf_getsegcount == NULL )
-    {
-        PyErr_BadArgument();
-        return -1;
-    }
-    if ( (*pb->bf_getsegcount)(value, NULL) != 1 )
-    {
-        /* ### use a different exception type/message? */
-        PyErr_SetString(PyExc_TypeError,
-                        "single-segment buffer object expected");
-        return -1;
-    }
-    if (!get_buf(self, &ptr1, &selfsize, ANY_BUFFER))
-        return -1;
-    if (PyIndex_Check(item)) {
-        Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
-        if (i == -1 && PyErr_Occurred())
-            return -1;
-        if (i < 0)
-            i += selfsize;
-        return buffer_ass_item(self, i, value);
-    }
-    else if (PySlice_Check(item)) {
-        Py_ssize_t start, stop, step, slicelength;
-
-        if (PySlice_GetIndicesEx((PySliceObject *)item, selfsize,
-                        &start, &stop, &step, &slicelength) < 0)
-            return -1;
-
-        if ((othersize = (*pb->bf_getreadbuffer)(value, 0, &ptr2)) < 0)
-            return -1;
-
-        if (othersize != slicelength) {
-            PyErr_SetString(
-                PyExc_TypeError,
-                "right operand length must match slice length");
-            return -1;
-        }
-
-        if (slicelength == 0)
-            return 0;
-        else if (step == 1) {
-            memcpy((char *)ptr1 + start, ptr2, slicelength);
-            return 0;
-        }
-        else {
-            Py_ssize_t cur, i;
-
-            for (cur = start, i = 0; i < slicelength;
-                 cur += step, i++) {
-                ((char *)ptr1)[cur] = ((char *)ptr2)[i];
-            }
-
-            return 0;
-        }
-    } else {
-        PyErr_SetString(PyExc_TypeError,
-                        "buffer indices must be integers");
-        return -1;
-    }
-}
-
-/* Buffer methods */
-
-static Py_ssize_t
-buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
-{
-    Py_ssize_t size;
-    if ( idx != 0 ) {
-        PyErr_SetString(PyExc_SystemError,
-                        "accessing non-existent buffer segment");
-        return -1;
-    }
-    if (!get_buf(self, pp, &size, READ_BUFFER))
-        return -1;
-    return size;
-}
-
-static Py_ssize_t
-buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
-{
-    Py_ssize_t size;
-
-    if ( self->b_readonly )
-    {
-        PyErr_SetString(PyExc_TypeError, "buffer is read-only");
-        return -1;
-    }
-
-    if ( idx != 0 ) {
-        PyErr_SetString(PyExc_SystemError,
-                        "accessing non-existent buffer segment");
-        return -1;
-    }
-    if (!get_buf(self, pp, &size, WRITE_BUFFER))
-        return -1;
-    return size;
-}
-
-static Py_ssize_t
-buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp)
-{
-    void *ptr;
-    Py_ssize_t size;
-    if (!get_buf(self, &ptr, &size, ANY_BUFFER))
-        return -1;
-    if (lenp)
-        *lenp = size;
-    return 1;
-}
-
-static Py_ssize_t
-buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp)
-{
-    void *ptr;
-    Py_ssize_t size;
-    if ( idx != 0 ) {
-        PyErr_SetString(PyExc_SystemError,
-                        "accessing non-existent buffer segment");
-        return -1;
-    }
-    if (!get_buf(self, &ptr, &size, CHAR_BUFFER))
-        return -1;
-    *pp = (const char *)ptr;
-    return size;
-}
-
-void init_bufferobject(void)
-{
-    PyType_Ready(&PyBuffer_Type);
-}
-
-static PySequenceMethods buffer_as_sequence = {
-    (lenfunc)buffer_length, /*sq_length*/
-    (binaryfunc)buffer_concat, /*sq_concat*/
-    (ssizeargfunc)buffer_repeat, /*sq_repeat*/
-    (ssizeargfunc)buffer_item, /*sq_item*/
-    (ssizessizeargfunc)buffer_slice, /*sq_slice*/
-    (ssizeobjargproc)buffer_ass_item, /*sq_ass_item*/
-    (ssizessizeobjargproc)buffer_ass_slice, /*sq_ass_slice*/
-};
-
-static PyMappingMethods buffer_as_mapping = {
-    (lenfunc)buffer_length,
-    (binaryfunc)buffer_subscript,
-    (objobjargproc)buffer_ass_subscript,
-};
-
-static PyBufferProcs buffer_as_buffer = {
-    (readbufferproc)buffer_getreadbuf,
-    (writebufferproc)buffer_getwritebuf,
-    (segcountproc)buffer_getsegcount,
-    (charbufferproc)buffer_getcharbuf,
-};
-
-PyTypeObject PyBuffer_Type = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    "buffer",
-    sizeof(PyBufferObject),
-    0,
-    (destructor)buffer_dealloc,                 /* tp_dealloc */
-    0,                                          /* tp_print */
-    0,                                          /* tp_getattr */
-    0,                                          /* tp_setattr */
-    (cmpfunc)buffer_compare,                    /* tp_compare */
-    (reprfunc)buffer_repr,                      /* tp_repr */
-    0,                                          /* tp_as_number */
-    &buffer_as_sequence,                        /* tp_as_sequence */
-    &buffer_as_mapping,                         /* tp_as_mapping */
-    (hashfunc)buffer_hash,                      /* tp_hash */
-    0,                                          /* tp_call */
-    (reprfunc)buffer_str,                       /* tp_str */
-    PyObject_GenericGetAttr,                    /* tp_getattro */
-    0,                                          /* tp_setattro */
-    &buffer_as_buffer,                          /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER, /* tp_flags */
-    buffer_doc,                                 /* tp_doc */
-    0,                                          /* tp_traverse */
-    0,                                          /* tp_clear */
-    0,                                          /* tp_richcompare */
-    0,                                          /* tp_weaklistoffset */
-    0,                                          /* tp_iter */
-    0,                                          /* tp_iternext */
-    0,                                          /* tp_methods */
-    0,                                          /* tp_members */
-    0,                                          /* tp_getset */
-    0,                                          /* tp_base */
-    0,                                          /* tp_dict */
-    0,                                          /* tp_descr_get */
-    0,                                          /* tp_descr_set */
-    0,                                          /* tp_dictoffset */
-    0,                                          /* tp_init */
-    0,                                          /* tp_alloc */
-    buffer_new,                                 /* tp_new */
-};
diff --git a/pypy/module/cpyext/test/array.c b/pypy/module/cpyext/test/array.c
--- a/pypy/module/cpyext/test/array.c
+++ b/pypy/module/cpyext/test/array.c
@@ -1484,7 +1484,7 @@
 \n\
 Extends this array with data from the unicode string ustr.\n\
 The array must be a unicode type array; otherwise a ValueError\n\
-is raised.  Use array.frombytes(ustr.decode(...)) to\n\
+is raised.  Use array.frombytes(ustr.encode(...)) to\n\
 append Unicode data to an array of some other type.");
 
 
@@ -1506,7 +1506,7 @@
 \n\
 Convert the array to a unicode string.  The array must be\n\
 a unicode type array; otherwise a ValueError is raised.  Use\n\
-array.tostring().decode() to obtain a unicode string from\n\
+array.tobytes().decode() to obtain a unicode string from\n\
 an array of some other type.");
 
 
@@ -2543,7 +2543,7 @@
 \n\
 Return a new array whose items are restricted by typecode, and\n\
 initialized from the optional initializer value, which must be a list,\n\
-string. or iterable over elements of the appropriate type.\n\
+string or iterable over elements of the appropriate type.\n\
 \n\
 Arrays represent basic values and behave very much like lists, except\n\
 the type of objects stored in them is constrained.\n\
@@ -2557,7 +2557,7 @@
 extend() -- extend array by appending multiple elements from an iterable\n\
 fromfile() -- read items from a file object\n\
 fromlist() -- append items from the list\n\
-fromstring() -- append items from the string\n\
+frombytes() -- append items from the string\n\
 index() -- return index of first occurrence of an object\n\
 insert() -- insert a new item into the array at a provided position\n\
 pop() -- remove and return item (default last)\n\
@@ -2565,7 +2565,7 @@
 reverse() -- reverse the order of the items in the array\n\
 tofile() -- write all items to a file object\n\
 tolist() -- return the array converted to an ordinary list\n\
-tostring() -- return the array converted to a string\n\
+tobytes() -- return the array converted to a string\n\
 \n\
 Attributes:\n\
 \n\
diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c
--- a/pypy/module/cpyext/test/foo.c
+++ b/pypy/module/cpyext/test/foo.c
@@ -115,7 +115,7 @@
 {
     PyObject *format;
 
-    format = PyString_FromString("<Foo>");
+    format = PyUnicode_FromString("<Foo>");
     if (format == NULL) return NULL;
     return format;
 }
@@ -131,11 +131,11 @@
 foo_setattro(fooobject *self, PyObject *name, PyObject *value)
 {
     char *name_str;
-    if (!PyString_Check(name)) {
+    if (!PyUnicode_Check(name)) {
         PyErr_SetObject(PyExc_AttributeError, name);
         return -1;
     }
-    name_str = PyString_AsString(name);
+    name_str = _PyUnicode_AsString(name);
     if (strcmp(name_str, "set_foo") == 0)
     {
         long v = PyInt_AsLong(value);
diff --git a/pypy/module/cpyext/test/sre.h b/pypy/module/cpyext/test/sre.h
--- a/pypy/module/cpyext/test/sre.h
+++ b/pypy/module/cpyext/test/sre.h
@@ -30,6 +30,8 @@
     PyObject* pattern; /* pattern source (or None) */
     int flags; /* flags used when compiling pattern source */
     PyObject *weakreflist; /* List of weak references */
+	int charsize; /* pattern charsize (or -1) */
+    Py_buffer view;
     /* pattern code */
     Py_ssize_t codesize;
     SRE_CODE code[1];
@@ -79,6 +81,7 @@
     char* data_stack;
     size_t data_stack_size;
     size_t data_stack_base;
+    Py_buffer buffer;
     /* current repeat context */
     SRE_REPEAT *repeat;
     /* hooks */
diff --git a/pypy/module/cpyext/test/test_arraymodule.py b/pypy/module/cpyext/test/test_arraymodule.py
--- a/pypy/module/cpyext/test/test_arraymodule.py
+++ b/pypy/module/cpyext/test/test_arraymodule.py
@@ -57,8 +57,8 @@
         module = self.import_module(name='array')
         arr = module.array('i', [1,2,3,4])
         # XXX big-endian
-        assert str(buffer(arr)) == ('\x01\0\0\0'
-                                    '\x02\0\0\0'
-                                    '\x03\0\0\0'
-                                    '\x04\0\0\0')
+        assert memoryview(arr).tobytes() == (b'\x01\0\0\0'
+                                             b'\x02\0\0\0'
+                                             b'\x03\0\0\0'
+                                             b'\x04\0\0\0')
 
diff --git a/pypy/module/cpyext/test/test_bufferobject.py b/pypy/module/cpyext/test/test_bufferobject.py
deleted file mode 100644
--- a/pypy/module/cpyext/test/test_bufferobject.py
+++ /dev/null
@@ -1,64 +0,0 @@
-from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.test.test_api import BaseApiTest
-from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
-from pypy.module.cpyext.api import PyObject
-from pypy.module.cpyext.pyobject import Py_DecRef
-
-class AppTestBufferObject(AppTestCpythonExtensionBase):
-    def test_FromMemory(self):
-        module = self.import_extension('foo', [
-            ("get_FromMemory", "METH_NOARGS",
-             """
-                 cbuf = malloc(4);
-                 cbuf[0] = 'a';
-                 cbuf[1] = 'b';
-                 cbuf[2] = 'c';
-                 cbuf[3] = '\\0';
-                 return PyBuffer_FromMemory(cbuf, 4);
-             """),
-            ("free_buffer", "METH_NOARGS",
-             """
-                 free(cbuf);
-                 Py_RETURN_NONE;
-             """),
-            ("check_ascharbuffer", "METH_O",
-             """
-                 char *ptr;
-                 Py_ssize_t size;
-                 if (PyObject_AsCharBuffer(args, &ptr, &size) < 0)
-                     return NULL;
-                 return PyString_FromStringAndSize(ptr, size);
-             """)
-            ], prologue = """
-            static char* cbuf = NULL;
-            """)
-        buf = module.get_FromMemory()
-        assert str(buf) == 'abc\0'
-
-        assert module.check_ascharbuffer(buf) == 'abc\0'
-
-        module.free_buffer()
-
-    def test_Buffer_New(self):
-        module = self.import_extension('foo', [
-            ("buffer_new", "METH_NOARGS",
-             """
-                 return PyBuffer_New(150);
-             """),
-            ])
-        b = module.buffer_new()
-        raises(AttributeError, getattr, b, 'x')
-
-    def test_array_buffer(self):
-        module = self.import_extension('foo', [
-            ("roundtrip", "METH_O",
-             """
-                 PyBufferObject *buf = (PyBufferObject *)args;
-                 return PyString_FromStringAndSize(buf->b_ptr, buf->b_size);
-             """),
-            ])
-        import array
-        a = array.array('c', 'text')
-        b = buffer(a)
-        assert module.roundtrip(b) == 'text'
-        
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -508,15 +508,10 @@
         """
         module = self.import_module(name='foo', init=init, body=body)
         assert module.return_pi() == 3.14
-        print "A"
         module.drop_pi()
-        print "B"
         module.drop_pi()
-        print "C"
         assert module.return_pi() == 3.14
-        print "D"
         assert module.return_pi() == 3.14
-        print "E"
         module.drop_pi()
         skip("Hmm, how to check for the exception?")
         raises(api.InvalidPointerException, module.return_invalid_pointer)
@@ -738,12 +733,12 @@
              char* name2 = Py_GetProgramName();
              if (name1 != name2)
                  Py_RETURN_FALSE;
-             return PyString_FromString(name1);
+             return PyUnicode_FromString(name1);
              '''
              ),
             ])
         p = mod.get_programname()
-        print p
+        print(p)
         assert 'py' in p
 
     def test_get_version(self):
@@ -754,12 +749,12 @@
              char* name2 = Py_GetVersion();
              if (name1 != name2)
                  Py_RETURN_FALSE;
-             return PyString_FromString(name1);
+             return PyUnicode_FromString(name1);
              '''
              ),
             ])
         p = mod.get_version()
-        print p
+        print(p)
         assert 'PyPy' in p
 
     def test_no_double_imports(self):
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
@@ -11,7 +11,7 @@
     generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
     Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
     Py_TPFLAGS_HAVE_GETCHARBUFFER,
-    build_type_checkers, PyObjectFields)
+    build_type_checkers, PyObjectFields, Py_buffer)
 from pypy.module.cpyext.pyobject import (
     PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
     track_reference, RefcountState, borrow_from)
@@ -28,7 +28,6 @@
     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
@@ -387,72 +386,24 @@
     # hopefully this does not clash with the memory model assumed in
     # extension modules
 
- at cpython_api([PyObject, Py_ssize_tP], lltype.Signed, external=False,
-             error=CANNOT_FAIL)
-def str_segcount(space, w_obj, ref):
-    if ref:
-        ref[0] = space.len_w(w_obj)
-    return 1
-
- at cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
-             external=False, error=-1)
-def str_getreadbuffer(space, w_str, segment, ref):
+ at cpython_api([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real], rffi.INT_real,
+              external=False, error=-1)
+def str_getbuffer(space, w_str, view, flags):
     from pypy.module.cpyext.stringobject import PyString_AsString
-    if segment != 0:
-        raise OperationError(space.w_SystemError, space.wrap
-                             ("accessing non-existent string segment"))
-    pyref = make_ref(space, w_str)
-    ref[0] = PyString_AsString(space, pyref)
-    # Stolen reference: the object has better exist somewhere else
-    Py_DecRef(space, pyref)
-    return space.len_w(w_str)
-
- at cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
-             external=False, error=-1)
-def str_getcharbuffer(space, w_str, segment, ref):
-    from pypy.module.cpyext.stringobject import PyString_AsString
-    if segment != 0:
-        raise OperationError(space.w_SystemError, space.wrap
-                             ("accessing non-existent string segment"))
-    pyref = make_ref(space, w_str)
-    ref[0] = PyString_AsString(space, pyref)
-    # Stolen reference: the object has better exist somewhere else
-    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
+    view.c_obj = make_ref(space, w_str)
+    view.c_buf = rffi.cast(rffi.VOIDP, PyString_AsString(space, view.c_obj))
+    view.c_len = space.len_w(w_str)
+    return 0
 
 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,
-                                 str_getreadbuffer.api_func.get_wrapper(space))
-    c_buf.c_bf_getcharbuffer = llhelper(str_getcharbuffer.api_func.functype,
-                                 str_getcharbuffer.api_func.get_wrapper(space))
+    c_buf.c_bf_getbuffer = llhelper(
+        str_getbuffer.api_func.functype,
+        str_getbuffer.api_func.get_wrapper(space))
     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
@@ -508,8 +459,6 @@
     # 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))
diff --git a/pypy/module/cpyext/typeobjectdefs.py b/pypy/module/cpyext/typeobjectdefs.py
--- a/pypy/module/cpyext/typeobjectdefs.py
+++ b/pypy/module/cpyext/typeobjectdefs.py
@@ -1,7 +1,7 @@
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.lltypesystem.lltype import Ptr, FuncType, Void
 from pypy.module.cpyext.api import (cpython_struct, Py_ssize_t, Py_ssize_tP,
-    PyVarObjectFields, PyTypeObject, PyTypeObjectPtr, FILEP,
+    PyVarObjectFields, PyTypeObject, PyTypeObjectPtr, FILEP, Py_buffer,
     Py_TPFLAGS_READYING, Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE)
 from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
 from pypy.module.cpyext.modsupport import PyMethodDef
@@ -53,13 +53,8 @@
 wrapperfunc = P(FT([PyO, PyO, rffi.VOIDP], PyO))
 wrapperfunc_kwds = P(FT([PyO, PyO, rffi.VOIDP, PyO], PyO))
 
-readbufferproc = P(FT([PyO, Py_ssize_t, rffi.VOIDPP], Py_ssize_t))
-writebufferproc = P(FT([PyO, Py_ssize_t, rffi.VOIDPP], Py_ssize_t))
-segcountproc = P(FT([PyO, Py_ssize_tP], Py_ssize_t))
-charbufferproc = P(FT([PyO, Py_ssize_t, rffi.CCHARPP], Py_ssize_t))
-## We don't support new buffer interface for now
-getbufferproc = rffi.VOIDP
-releasebufferproc = rffi.VOIDP
+getbufferproc = P(FT([PyO, Ptr(Py_buffer), rffi.INT_real], rffi.INT_real))
+releasebufferproc = P(FT([PyO, Ptr(Py_buffer)], Void))
 
 
 PyGetSetDef = cpython_struct("PyGetSetDef", (
@@ -131,10 +126,6 @@
 ))
 
 PyBufferProcs = cpython_struct("PyBufferProcs", (
-    ("bf_getreadbuffer", readbufferproc),
-    ("bf_getwritebuffer", writebufferproc),
-    ("bf_getsegcount", segcountproc),
-    ("bf_getcharbuffer", charbufferproc),
     ("bf_getbuffer", getbufferproc),
     ("bf_releasebuffer", releasebufferproc),
 ))


More information about the pypy-commit mailing list