py3k: Use new buffer protocol

Other ports have taken advantage of the fact that Python 3 has wrappers for
the old buffer protocol, but there's a significant disadvantage: you can't
let the buffered object know when you're done with it.

Since Python 2.6 supports the new protocol, we just go ahead and move to
it.
This commit is contained in:
Brian Crowell 2012-10-20 16:13:12 -05:00 committed by Brian Crowell
parent 9519013466
commit 804095ecb3
3 changed files with 50 additions and 60 deletions

View File

@ -103,19 +103,6 @@
#define L16(p, i) ((((int)p[(i)+1]) << 8) + p[(i)]) #define L16(p, i) ((((int)p[(i)+1]) << 8) + p[(i)])
#define S16(v) ((v) < 32768 ? (v) : ((v) - 65536)) #define S16(v) ((v) < 32768 ? (v) : ((v) - 65536))
#if PY_VERSION_HEX < 0x01060000
#define PyObject_New PyObject_NEW
#define PyObject_Del PyMem_DEL
#endif
#if PY_VERSION_HEX < 0x02050000
#define Py_ssize_t int
#define ssizeargfunc intargfunc
#define ssizessizeargfunc intintargfunc
#define ssizeobjargproc intobjargproc
#define ssizessizeobjargproc intintobjargproc
#endif
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* OBJECT ADMINISTRATION */ /* OBJECT ADMINISTRATION */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
@ -243,43 +230,38 @@ void ImagingSectionLeave(ImagingSectionCookie* cookie)
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Python compatibility API */ /* Python compatibility API */
#if PY_VERSION_HEX < 0x02020000
int PyImaging_CheckBuffer(PyObject *buffer)
{
PyBufferProcs *procs = buffer->ob_type->tp_as_buffer;
if (procs && procs->bf_getreadbuffer && procs->bf_getsegcount &&
procs->bf_getsegcount(buffer, NULL) == 1)
return 1;
return 0;
}
int PyImaging_ReadBuffer(PyObject* buffer, const void** ptr)
{
PyBufferProcs *procs = buffer->ob_type->tp_as_buffer;
return procs->bf_getreadbuffer(buffer, 0, ptr);
}
#else
int PyImaging_CheckBuffer(PyObject* buffer) int PyImaging_CheckBuffer(PyObject* buffer)
{ {
return PyObject_CheckReadBuffer(buffer); #if PY_VERSION_HEX >= 0x03000000
return PyObject_CheckBuffer(buffer);
#else
return PyObject_CheckBuffer(buffer) || PyObject_CheckReadBuffer(buffer);
#endif
} }
int PyImaging_ReadBuffer(PyObject* buffer, const void** ptr) int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view)
{ {
/* must call check_buffer first! */ /* must call check_buffer first! */
#if PY_VERSION_HEX < 0x02050000 #if PY_VERSION_HEX >= 0x03000000
int n = 0; return PyObject_GetBuffer(buffer, view, PyBUF_SIMPLE);
#else #else
Py_ssize_t n = 0; /* Use new buffer protocol if available
#endif (mmap doesn't support this in 2.7, go figure) */
PyObject_AsReadBuffer(buffer, ptr, &n); if (PyObject_CheckBuffer(buffer)) {
return (int) n; return PyObject_GetBuffer(buffer, view, PyBUF_SIMPLE);
} }
/* Pretend we support the new protocol; PyBuffer_Release happily ignores
calling bf_releasebuffer on objects that don't support it */
*view = (Py_buffer) {0};
view->readonly = 1;
Py_INCREF(buffer);
view->obj = buffer;
return PyObject_AsReadBuffer(buffer, (void *) &view->buf, &view->len);
#endif #endif
}
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* EXCEPTION REROUTING */ /* EXCEPTION REROUTING */

20
map.c
View File

@ -41,7 +41,7 @@
/* compatibility wrappers (defined in _imaging.c) */ /* compatibility wrappers (defined in _imaging.c) */
extern int PyImaging_CheckBuffer(PyObject* buffer); extern int PyImaging_CheckBuffer(PyObject* buffer);
extern int PyImaging_ReadBuffer(PyObject* buffer, const void** ptr); extern int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view);
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Standard mapper */ /* Standard mapper */
@ -311,6 +311,7 @@ PyImaging_Mapper(PyObject* self, PyObject* args)
typedef struct ImagingBufferInstance { typedef struct ImagingBufferInstance {
struct ImagingMemoryInstance im; struct ImagingMemoryInstance im;
PyObject* target; PyObject* target;
Py_buffer view;
} ImagingBufferInstance; } ImagingBufferInstance;
static void static void
@ -318,6 +319,7 @@ mapping_destroy_buffer(Imaging im)
{ {
ImagingBufferInstance* buffer = (ImagingBufferInstance*) im; ImagingBufferInstance* buffer = (ImagingBufferInstance*) im;
PyBuffer_Release(&buffer->view);
Py_XDECREF(buffer->target); Py_XDECREF(buffer->target);
} }
@ -326,10 +328,9 @@ PyImaging_MapBuffer(PyObject* self, PyObject* args)
{ {
int y, size; int y, size;
Imaging im; Imaging im;
char* ptr;
int bytes;
PyObject* target; PyObject* target;
Py_buffer view;
char* mode; char* mode;
char* codec; char* codec;
PyObject* bbox; PyObject* bbox;
@ -359,12 +360,14 @@ PyImaging_MapBuffer(PyObject* self, PyObject* args)
size = ysize * stride; size = ysize * stride;
/* check buffer size */ /* check buffer size */
bytes = PyImaging_ReadBuffer(target, (const void**) &ptr); if (PyImaging_GetBuffer(target, &view) < 0)
if (bytes < 0) { return NULL;
if (view.len < 0) {
PyErr_SetString(PyExc_ValueError, "buffer has negative size"); PyErr_SetString(PyExc_ValueError, "buffer has negative size");
return NULL; return NULL;
} }
if (offset + size > bytes) { if (offset + size > view.len) {
PyErr_SetString(PyExc_ValueError, "buffer is not large enough"); PyErr_SetString(PyExc_ValueError, "buffer is not large enough");
return NULL; return NULL;
} }
@ -378,15 +381,16 @@ PyImaging_MapBuffer(PyObject* self, PyObject* args)
/* setup file pointers */ /* setup file pointers */
if (ystep > 0) if (ystep > 0)
for (y = 0; y < ysize; y++) for (y = 0; y < ysize; y++)
im->image[y] = ptr + offset + y * stride; im->image[y] = view.buf + offset + y * stride;
else else
for (y = 0; y < ysize; y++) for (y = 0; y < ysize; y++)
im->image[ysize-y-1] = ptr + offset + y * stride; im->image[ysize-y-1] = view.buf + offset + y * stride;
im->destroy = mapping_destroy_buffer; im->destroy = mapping_destroy_buffer;
Py_INCREF(target); Py_INCREF(target);
((ImagingBufferInstance*) im)->target = target; ((ImagingBufferInstance*) im)->target = target;
((ImagingBufferInstance*) im)->view = view;
if (!ImagingNewEpilogue(im)) if (!ImagingNewEpilogue(im))
return NULL; return NULL;

26
path.c
View File

@ -46,7 +46,7 @@
/* compatibility wrappers (defined in _imaging.c) */ /* compatibility wrappers (defined in _imaging.c) */
extern int PyImaging_CheckBuffer(PyObject* buffer); extern int PyImaging_CheckBuffer(PyObject* buffer);
extern int PyImaging_ReadBuffer(PyObject* buffer, const void** ptr); extern int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view);
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Class */ /* Class */
@ -134,16 +134,20 @@ PyPath_Flatten(PyObject* data, double **pxy)
if (PyImaging_CheckBuffer(data)) { if (PyImaging_CheckBuffer(data)) {
/* Assume the buffer contains floats */ /* Assume the buffer contains floats */
float* ptr; Py_buffer buffer;
int n = PyImaging_ReadBuffer(data, (const void**) &ptr); if (PyImaging_GetBuffer(data, &buffer) == 0) {
n /= 2 * sizeof(float); int n = buffer.len / (2 * sizeof(float));
xy = alloc_array(n); float *ptr = (float*) buffer.buf;
if (!xy) xy = alloc_array(n);
return -1; if (!xy)
for (i = 0; i < n+n; i++) return -1;
xy[i] = ptr[i]; for (i = 0; i < n+n; i++)
*pxy = xy; xy[i] = ptr[i];
return n; *pxy = xy;
PyBuffer_Release(&buffer);
return n;
}
PyErr_Clear();
} }
if (!PySequence_Check(data)) { if (!PySequence_Check(data)) {