[Python-Dev] An updated extended buffer PEP
Carl Banks
pythondev at aerojockey.com
Wed Mar 28 15:24:29 CEST 2007
Carl Banks wrote:
> Here's a concrete example of where it would be useful: consider a
> ByteBufferSlice object. Basically, the object represents a
> shared-memory slice of a 1-D array of bytes (for example, Python 3000
> bytes object, or an mmap object).
>
> Now, if the ByteBufferSlice object could tell the consumer that someone
> else is managing the buffer, then it wouldn't have to keep track of
> views, thus simplifying things.
>
> P.S. In thinking about this, it occurred to me that there should be a
> way to lock the buffer without requesting details. ByteBufferSlice
> would already know the details of the buffer, but it would need to
> increment the original buffer's lock count. Thus, I propose new fuction:
>
> typedef int (*lockbufferproc)(PyObject* self);
And, because real examples are better than philosophical speculations,
here's a skeleton implementation of the ByteBufferSlice array, sans
boilerplate and error checking, and with some educated guessing about
future details:
typedef struct {
PyObject_HEAD
PyObject* releaser;
unsigned char* buf;
Py_ssize_t length;
}
ByteBufferSliceObject;
PyObject* ByteBufferSlice_new(PyObject* bufobj, Py_ssize_t start,
Py_ssize_t end) {
ByteBufferSliceObject* self;
BufferInfoObject* bufinfo;
self = (ByteBufferSliceObject*)type->tp_alloc(type, 0);
bufinfo = PyObject_GetBuffer(bufobj);
self->releaser = bufinfo->releaser;
self->buf = bufinfo->buf + start;
self->length = end-start;
/* look how soon we're done with this information */
Py_DECREF(bufinfo);
return self;
}
PyObject* ByteBufferSlice_dealloc(PyObject* self) {
PyObject_ReleaseBuffer(self->releaser);
self->ob_type->tp_free((PyObject*)self);
}
PyObject* ByteBufferSlice_getbuffer(PyObject* self, int flags) {
BufferInfoObject* bufinfo;
static Py_ssize_t stridesarray[] = { 1 };
bufinfo = BufferInfo_New();
bufinfo->releaser = self->releaser;
bufinfo->writable = 1;
bufinfo->buf = self->buf;
bufinfo->length = self->length;
bufinfo->ndims = 1;
bufinfo->strides = stridesarray;
bufinfo->size = &self->length;
bufinfo->subbufoffsets = NULL;
/* Before we go, increase the original buffer's lock count */
PyObject_LockBuffer(self->releaser);
return bufinfo;
}
/* don't define releasebuffer or lockbuffer */
/* only objects that manage buffers themselves would define these */
/* Now look how easy this is */
/* Everything works out if ByteBufferSlice reexports the buffer */
PyObject* ByteBufferSlice_getslice(PyObject* self, Py_ssize_t start,
Py_ssize_t end) {
return ByteBufferSlice_new(self,start,end);
}
The implementation of this is very straightforward, and it's easy to see
why and how "bufinfo->release" works, and why it'd be useful.
It's almost like there's two protocols here: a buffer exporter protocol
(getbuffer) and a buffer manager protocol (lockbuffer and
releasebuffer). Some objects would support only exporter protocol;
others both.
Carl Banks
More information about the Python-Dev
mailing list