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 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 */
/* -------------------------------------------------------------------- */
@ -243,43 +230,38 @@ void ImagingSectionLeave(ImagingSectionCookie* cookie)
/* -------------------------------------------------------------------- */
/* 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)
{
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! */
#if PY_VERSION_HEX < 0x02050000
int n = 0;
#if PY_VERSION_HEX >= 0x03000000
return PyObject_GetBuffer(buffer, view, PyBUF_SIMPLE);
#else
Py_ssize_t n = 0;
#endif
PyObject_AsReadBuffer(buffer, ptr, &n);
return (int) n;
}
/* Use new buffer protocol if available
(mmap doesn't support this in 2.7, go figure) */
if (PyObject_CheckBuffer(buffer)) {
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
}
/* -------------------------------------------------------------------- */
/* EXCEPTION REROUTING */

20
map.c
View File

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

26
path.c
View File

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