2007-04-09 01:51:32 -04:00
|
|
|
PEP: 3118
|
|
|
|
Title: Revising the buffer protocol
|
|
|
|
Version: $Revision$
|
|
|
|
Last-Modified: $Date$
|
2007-04-27 02:58:33 -04:00
|
|
|
Author: Travis Oliphant <oliphant@ee.byu.edu>, Carl Banks <pythondev@aerojockey.com>
|
2007-04-09 01:51:32 -04:00
|
|
|
Status: Draft
|
|
|
|
Type: Standards Track
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
Created: 28-Aug-2006
|
|
|
|
Python-Version: 3000
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
========
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
This PEP proposes re-designing the buffer interface (``PyBufferProcs``
|
2007-04-26 17:43:28 -04:00
|
|
|
function pointers) to improve the way Python allows memory sharing in
|
|
|
|
Python 3.0
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
In particular, it is proposed that the character buffer portion
|
|
|
|
of the API be elminated and the multiple-segment portion be
|
|
|
|
re-designed in conjunction with allowing for strided memory
|
|
|
|
to be shared. In addition, the new buffer interface will
|
|
|
|
allow the sharing of any multi-dimensional nature of the
|
|
|
|
memory and what data-format the memory contains.
|
|
|
|
|
|
|
|
This interface will allow any extension module to either
|
|
|
|
create objects that share memory or create algorithms that
|
|
|
|
use and manipulate raw memory from arbitrary objects that
|
|
|
|
export the interface.
|
|
|
|
|
|
|
|
|
|
|
|
Rationale
|
|
|
|
=========
|
|
|
|
|
|
|
|
The Python 2.X buffer protocol allows different Python types to
|
|
|
|
exchange a pointer to a sequence of internal buffers. This
|
|
|
|
functionality is *extremely* useful for sharing large segments of
|
|
|
|
memory between different high-level objects, but it is too limited and
|
|
|
|
has issues:
|
|
|
|
|
|
|
|
1. There is the little used "sequence-of-segments" option
|
|
|
|
(bf_getsegcount) that is not well motivated.
|
|
|
|
|
|
|
|
2. There is the apparently redundant character-buffer option
|
|
|
|
(bf_getcharbuffer)
|
|
|
|
|
|
|
|
3. There is no way for a consumer to tell the buffer-API-exporting
|
|
|
|
object it is "finished" with its view of the memory and
|
|
|
|
therefore no way for the exporting object to be sure that it is
|
|
|
|
safe to reallocate the pointer to the memory that it owns (for
|
|
|
|
example, the array object reallocating its memory after sharing
|
|
|
|
it with the buffer object which held the original pointer led
|
|
|
|
to the infamous buffer-object problem).
|
|
|
|
|
|
|
|
4. Memory is just a pointer with a length. There is no way to
|
|
|
|
describe what is "in" the memory (float, int, C-structure, etc.)
|
|
|
|
|
|
|
|
5. There is no shape information provided for the memory. But,
|
|
|
|
several array-like Python types could make use of a standard
|
|
|
|
way to describe the shape-interpretation of the memory
|
|
|
|
(wxPython, GTK, pyQT, CVXOPT, PyVox, Audio and Video
|
|
|
|
Libraries, ctypes, NumPy, data-base interfaces, etc.)
|
|
|
|
|
|
|
|
6. There is no way to share discontiguous memory (except through
|
|
|
|
the sequence of segments notion).
|
|
|
|
|
|
|
|
There are two widely used libraries that use the concept of
|
|
|
|
discontiguous memory: PIL and NumPy. Their view of discontiguous
|
|
|
|
arrays is different, though. The proposed buffer interface allows
|
|
|
|
sharing of either memory model. Exporters will use only one
|
|
|
|
approach and consumers may choose to support discontiguous
|
|
|
|
arrays of each type however they choose.
|
|
|
|
|
|
|
|
NumPy uses the notion of constant striding in each dimension as its
|
|
|
|
basic concept of an array. With this concept, a simple sub-region
|
2007-04-26 17:43:28 -04:00
|
|
|
of a larger array can be described without copying the data.
|
2007-04-09 01:51:32 -04:00
|
|
|
Thus, stride information is the additional information that must be
|
|
|
|
shared.
|
|
|
|
|
|
|
|
The PIL uses a more opaque memory representation. Sometimes an
|
|
|
|
image is contained in a contiguous segment of memory, but sometimes
|
|
|
|
it is contained in an array of pointers to the contiguous segments
|
|
|
|
(usually lines) of the image. The PIL is where the idea of multiple
|
|
|
|
buffer segments in the original buffer interface came from.
|
|
|
|
|
|
|
|
NumPy's strided memory model is used more often in computational
|
|
|
|
libraries and because it is so simple it makes sense to support
|
|
|
|
memory sharing using this model. The PIL memory model is sometimes
|
|
|
|
used in C-code where a 2-d array can be then accessed using double
|
2007-04-27 02:58:33 -04:00
|
|
|
pointer indirection: e.g. ``image[i][j]``.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
The buffer interface should allow the object to export either of these
|
|
|
|
memory models. Consumers are free to either require contiguous memory
|
|
|
|
or write code to handle one or both of these memory models.
|
|
|
|
|
|
|
|
Proposal Overview
|
|
|
|
=================
|
|
|
|
|
|
|
|
* Eliminate the char-buffer and multiple-segment sections of the
|
|
|
|
buffer-protocol.
|
|
|
|
|
|
|
|
* Unify the read/write versions of getting the buffer.
|
|
|
|
|
|
|
|
* Add a new function to the interface that should be called when
|
|
|
|
the consumer object is "done" with the memory area.
|
|
|
|
|
|
|
|
* Add a new variable to allow the interface to describe what is in
|
|
|
|
memory (unifying what is currently done now in struct and
|
|
|
|
array)
|
|
|
|
|
|
|
|
* Add a new variable to allow the protocol to share shape information
|
|
|
|
|
|
|
|
* Add a new variable for sharing stride information
|
|
|
|
|
|
|
|
* Add a new mechanism for sharing arrays that must
|
|
|
|
be accessed using pointer indirection.
|
|
|
|
|
|
|
|
* Fix all objects in the core and the standard library to conform
|
|
|
|
to the new interface
|
|
|
|
|
|
|
|
* Extend the struct module to handle more format specifiers
|
|
|
|
|
|
|
|
* Extend the buffer object into a new memory object which places
|
|
|
|
a Python veneer around the buffer interface.
|
|
|
|
|
|
|
|
* Add a few functions to make it easy to copy contiguous data
|
|
|
|
in and out of object supporting the buffer interface.
|
|
|
|
|
|
|
|
Specification
|
|
|
|
=============
|
|
|
|
|
|
|
|
While the new specification allows for complicated memory sharing.
|
|
|
|
Simple contiguous buffers of bytes can still be obtained from an
|
|
|
|
object. In fact, the new protocol allows a standard mechanism for
|
|
|
|
doing this even if the original object is not represented as a
|
|
|
|
contiguous chunk of memory.
|
|
|
|
|
2007-04-10 05:45:04 -04:00
|
|
|
The easiest way to obtain a simple contiguous chunk of memory is
|
|
|
|
to use the provided C-API to obtain a chunk of memory.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
Change the ``PyBufferProcs`` structure to ::
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
getbufferproc bf_getbuffer;
|
|
|
|
releasebufferproc bf_releasebuffer;
|
2007-04-27 02:58:33 -04:00
|
|
|
} PyBufferProcs;
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
::
|
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
typedef int (*getbufferproc)(PyObject *obj, PyBuffer *view, int flags)
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
This function returns ``0`` on success and ``-1`` on failure (and raises an
|
2007-04-09 01:51:32 -04:00
|
|
|
error). The first variable is the "exporting" object. The second
|
2007-04-27 02:58:33 -04:00
|
|
|
argument is the address to a bufferinfo structure. If view is ``NULL``,
|
2007-04-09 01:51:32 -04:00
|
|
|
then no information is returned but a lock on the memory is still
|
2007-04-10 05:45:04 -04:00
|
|
|
obtained. In this case, the corresponding releasebuffer should also
|
2007-04-27 02:58:33 -04:00
|
|
|
be called with ``NULL``.
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
The third argument indicates what kind of buffer the consumer is
|
|
|
|
prepared to deal with and therefore what kind of buffer the exporter
|
|
|
|
is allowed to return. The new buffer interface allows for much more
|
|
|
|
complicated memory sharing possibilities. Some consumers may not be
|
|
|
|
able to handle all the complexibity but may want to see if the
|
|
|
|
exporter will let them take a simpler view to its memory.
|
|
|
|
|
|
|
|
In addition, 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
|
2007-04-27 02:58:33 -04:00
|
|
|
``PyErr_BufferError`` unless there is another error that is actually
|
2007-04-26 17:43:28 -04:00
|
|
|
causing the problem. The exporter can use flags information to
|
|
|
|
simplify how much of the PyBuffer 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.
|
|
|
|
|
|
|
|
The exporter should always fill in all elements of the buffer
|
|
|
|
structure (with defaults if nothing else is requested).
|
|
|
|
|
|
|
|
Some flags are useful for requesting a specific kind of memory
|
|
|
|
segment, while others indicate to the exporter what kind of
|
|
|
|
information the consumer can deal with. If certain information is not
|
|
|
|
asked for by the consumer, but the exporter cannot share its memory
|
2007-04-27 02:58:33 -04:00
|
|
|
without that information, then a ``PyErr_BufferError`` should be raised.
|
2007-04-26 17:43:28 -04:00
|
|
|
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``PyBUF_SIMPLE``
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
This is the default flag state (0). The returned buffer may or may
|
|
|
|
not have writeable memory. The format will be assumed to be
|
|
|
|
unsigned bytes . This is a "stand-alone" flag constant. It never
|
2007-04-27 01:52:31 -04:00
|
|
|
needs to be \|'d to the others. The exporter will raise an error if
|
2007-04-26 17:43:28 -04:00
|
|
|
it cannot provide such a contiguous buffer of bytes.
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``PyBUF_REQ_WRITEABLE``
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
The returned buffer must be writeable. If it is not writeable,
|
|
|
|
then raise an error.
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``PyBUF_REQ_LOCKDATA``
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
The returned buffer must be readonly. If the object is already
|
|
|
|
read-only or it can make its memory read-only (and there are no
|
|
|
|
other views on the object) then it should do so and return the
|
|
|
|
buffer information. If the object does not have read-only memory
|
|
|
|
(or cannot make it read-only), then an error should be raised.
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``PyBUF_REQ_FORMAT``
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
The returned buffer must have true format information if this flag
|
|
|
|
is provided. This would be used when the consumer is going to be
|
|
|
|
checking for what 'kind' of data is actually stored. An exporter
|
|
|
|
should always be able to provide this information if requested. If
|
|
|
|
format is not explicitly requested then the format must be returned
|
2007-04-27 02:58:33 -04:00
|
|
|
as ``NULL`` (which means "B")
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``PyBUF_REQ_ALIGNED`` (implies ``PyBUF_REQ_FORMAT``)
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
The returned buffer must have all (primitive data-type entries)
|
|
|
|
aligned as the compiler would align them
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``PyBUF_ALW_ND``
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
The returned buffer must provide shape information. The memory will
|
|
|
|
be assumed C-style contiguous (last dimension varies the fastest).
|
|
|
|
The exporter may raise an error if it cannot provide this kind of
|
|
|
|
contiguous buffer.
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``PyBUF_ALW_STRIDES`` (implies ``PyBUF_ALW_ND``)
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
The returned buffer must provide strides information. This would be
|
|
|
|
used when the consumer can handle strided, discontiguous arrays.
|
|
|
|
Handling strides automatically assumes you can handle shape.
|
|
|
|
The exporter may raise an error if cannot provide a strided-only
|
|
|
|
representation of the data (i.e. without the suboffsets).
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
| ``PyBUF_REQ_C_CONTIGUOUS``
|
|
|
|
| ``PyBUF_REQ_F_CONTIGUOUS``
|
|
|
|
| ``PyBUF_REQ_ANY_CONTIGUOUS``
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
These flags indicate that the returned buffer must be respectively,
|
|
|
|
C-contiguous (last dimension varies the fastest), Fortran
|
|
|
|
contiguous (first dimension varies the fastest) or either one.
|
|
|
|
All of these flags imply PyBUF_ALW_STRIDES and guarantee that the
|
|
|
|
strides buffer info structure will be filled in correctly.
|
|
|
|
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``PyBUF_ALW_INDIRECT`` (implies ``PyBUF_ALW_STRIDES``)
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
The returned buffer must have suboffsets information. This would
|
|
|
|
be used when the consumer can handle indirect array referencing
|
|
|
|
implied by these suboffsets.
|
|
|
|
|
|
|
|
|
|
|
|
Specialized combinations of flags for specific kinds of memory_sharing.
|
|
|
|
|
|
|
|
Multi-dimensional (but contiguous)
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
| ``PyBUF_CONTIG`` (``PyBUF_ALW_ND | PyBUF_REQ_WRITEABLE | PyBUF_REQ_ALIGNED``)
|
|
|
|
| ``PyBUF_CONTIG_RO`` (``PyBUF_ALW_ND | PyBUF_REQ_ALIGNED``)
|
|
|
|
| ``PyBUF_CONTIG_LCK`` (``PyBUF_ALW_ND | PyBUF_REQ_LOCKDATA | PyBUF_REQ_ALIGNED``)
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
Multi-dimensional using strides but aligned
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
| ``PyBUF_STRIDED`` (``PyBUF_ALW_STRIDES | PyBUF_REQ_WRITEABLE | PyBUF_REQ_ALIGNED``)
|
|
|
|
| ``PyBUF_STRIDED_RO`` (``PyBUF_ALW_STRIDES | PyBUF_REQ_ALIGNED``)
|
|
|
|
| ``PyBUF_STRIDED_LCK`` (``PyBUF_ALW_STRIDES | PyBUF_REQ_LOCKDATA | PyBUF_REQ_ALIGNED``)
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
Multi-dimensional using strides and not necessarily aligned
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
| ``PyBUF_RECORDS`` (``PyBUF_ALW_STRIDES | PyBUF_REQ_WRITEABLE | PyBUF_REQ_FORMAT``)
|
|
|
|
| ``PyBUF_RECORDS_RO`` (``PyBUF_ALW_STRIDES | PyBUF_REQ_FORMAT``)
|
|
|
|
| ``PyBUF_RECORDS_LCK`` (``PyBUF_ALW_STRIDES | PyBUF_REQ_LOCKDATA | PyBUF_REQ_FORMAT``)
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
Multi-dimensional using sub-offsets
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
| ``PyBUF_FULL`` (``PyBUF_ALW_INDIRECT | PyBUF_REQ_WRITEABLE | PyBUF_REQ_FORMAT``)
|
|
|
|
| ``PyBUF_FULL_RO`` (``PyBUF_ALW_INDIRECT | PyBUF_REQ_FORMAT``)
|
|
|
|
| ``PyBUF_FULL_LCK`` (``PyBUF_ALW_INDIRECT | PyBUF_REQ_LOCKDATA | PyBUF_REQ_FORMAT``)
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
Thus, the consumer simply wanting a contiguous chunk of bytes from
|
2007-04-27 02:58:33 -04:00
|
|
|
the object would use ``PyBUF_SIMPLE``, while a consumer that understands
|
|
|
|
how to make use of the most complicated cases could use ``PyBUF_FULL``.
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
The format information is only guaranteed to be non-NULL if
|
2007-04-27 02:58:33 -04:00
|
|
|
``PyBUF_REQ_FORMAT`` is in the flag argument, otherwise it is expected the
|
2007-04-26 17:43:28 -04:00
|
|
|
consumer will assume unsigned bytes.
|
2007-04-10 05:45:04 -04:00
|
|
|
|
|
|
|
There is a C-API that simple exporting objects can use to fill-in the
|
|
|
|
buffer info structure correctly according to the provided flags if a
|
2007-04-26 17:43:28 -04:00
|
|
|
contiguous chunk of "unsigned bytes" is all that can be exported.
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
The bufferinfo structure is::
|
|
|
|
|
|
|
|
struct bufferinfo {
|
|
|
|
void *buf;
|
|
|
|
Py_ssize_t len;
|
|
|
|
int readonly;
|
2007-04-26 17:43:28 -04:00
|
|
|
const char *format;
|
|
|
|
int ndim;
|
2007-04-09 01:51:32 -04:00
|
|
|
Py_ssize_t *shape;
|
|
|
|
Py_ssize_t *strides;
|
|
|
|
Py_ssize_t *suboffsets;
|
2007-04-26 17:43:28 -04:00
|
|
|
int itemsize;
|
2007-04-10 05:45:04 -04:00
|
|
|
void *internal;
|
2007-04-26 17:43:28 -04:00
|
|
|
} PyBuffer;
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
Before calling this function, the bufferinfo structure can be filled
|
|
|
|
with whatever. Upon return from getbufferproc, the bufferinfo
|
|
|
|
structure is filled in with relevant information about the buffer.
|
|
|
|
This same bufferinfo structure must be passed to bf_releasebuffer (if
|
|
|
|
available) when the consumer is done with the memory. The caller is
|
|
|
|
responsible for keeping a reference to obj until releasebuffer is
|
|
|
|
called (i.e. the call to bf_getbuffer does not alter the reference
|
|
|
|
count of obj).
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
The members of the bufferinfo structure are:
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``buf``
|
2007-04-09 01:51:32 -04:00
|
|
|
a pointer to the start of the memory for the object
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``len``
|
2007-04-09 01:51:32 -04:00
|
|
|
the total bytes of memory the object uses. This should be the
|
|
|
|
same as the product of the shape array multiplied by the number of
|
|
|
|
bytes per item of memory.
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``readonly``
|
2007-04-26 17:43:28 -04:00
|
|
|
an integer variable to hold whether or not the memory is readonly.
|
|
|
|
1 means the memory is readonly, zero means the memory is
|
|
|
|
writeable, and -1 means the memory was "locked" (changed from
|
|
|
|
writeable to readonly) when this PyBuffer structure was filled-in
|
|
|
|
and therefore should be unlocked when this PyBuffer structure is
|
|
|
|
"released" (this is supported only by some exporters).
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``format``
|
2007-04-10 05:45:04 -04:00
|
|
|
a NULL-terminated format-string (following the struct-style syntax
|
|
|
|
including extensions) indicating what is in each element of
|
|
|
|
memory. The number of elements is len / itemsize, where itemsize
|
2007-04-26 17:43:28 -04:00
|
|
|
is the number of bytes implied by the format. This can be NULL which
|
|
|
|
implies standard unsigned bytes ("B").
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``ndims``
|
2007-04-09 01:51:32 -04:00
|
|
|
a variable storing the number of dimensions the memory represents.
|
2007-04-26 17:43:28 -04:00
|
|
|
Must be >=0. A value of 0 means that shape and strides and suboffsets
|
2007-04-27 02:58:33 -04:00
|
|
|
must be ``NULL`` (i.e. the memory represents a scalar).
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``shape``
|
2007-04-09 01:51:32 -04:00
|
|
|
an array of ``Py_ssize_t`` of length ``ndims`` indicating the
|
|
|
|
shape of the memory as an N-D array. Note that ``((*shape)[0] *
|
2007-04-26 17:43:28 -04:00
|
|
|
... * (*shape)[ndims-1])*itemsize = len``. If ndims is 0 (indicating
|
2007-04-27 02:58:33 -04:00
|
|
|
a scalar), then this must be ``NULL``.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``strides``
|
2007-04-09 01:51:32 -04:00
|
|
|
address of a ``Py_ssize_t*`` variable that will be filled with a
|
2007-04-27 02:58:33 -04:00
|
|
|
pointer to an array of ``Py_ssize_t`` of length ``ndims`` (or ``NULL``
|
|
|
|
if ``ndims`` is 0). indicating the number of bytes to skip to get to
|
2007-04-26 17:43:28 -04:00
|
|
|
the next element in each dimension. If this is not requested by
|
2007-04-27 02:58:33 -04:00
|
|
|
the caller (``PyBUF_ALW_STRIDES`` is not set), then this should be set
|
2007-04-26 17:43:28 -04:00
|
|
|
to NULL which indicates a C-style contiguous array.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``suboffsets``
|
2007-04-09 01:51:32 -04:00
|
|
|
address of a ``Py_ssize_t *`` variable that will be filled with a
|
|
|
|
pointer to an array of ``Py_ssize_t`` of length ``*ndims``. If
|
|
|
|
these suboffset numbers are >=0, then the value stored along the
|
|
|
|
indicated dimension is a pointer and the suboffset value dictates
|
|
|
|
how many bytes to add to the pointer after de-referencing. A
|
|
|
|
suboffset value that it negative indicates that no de-referencing
|
|
|
|
should occur (striding in a contiguous memory block). If all
|
|
|
|
suboffsets are negative (i.e. no de-referencing is needed, then
|
2007-04-26 17:43:28 -04:00
|
|
|
this must be NULL (the default value).
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
For clarity, here is a function that returns a pointer to the
|
|
|
|
element in an N-D array pointed to by an N-dimesional index when
|
2007-04-27 02:58:33 -04:00
|
|
|
there are both non-NULL strides and suboffsets::
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
void *get_item_pointer(int ndim, void *buf, Py_ssize_t *strides,
|
|
|
|
Py_ssize_t *suboffsets, Py_ssize_t *indices) {
|
|
|
|
char *pointer = (char*)buf;
|
2007-04-09 01:51:32 -04:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < ndim; i++) {
|
2007-04-27 02:58:33 -04:00
|
|
|
pointer += strides[i] * indices[i];
|
2007-04-09 01:51:32 -04:00
|
|
|
if (suboffsets[i] >=0 ) {
|
|
|
|
pointer = *((char**)pointer) + suboffsets[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (void*)pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
Notice the suboffset is added "after" the dereferencing occurs.
|
|
|
|
Thus slicing in the ith dimension would add to the suboffsets in
|
2007-04-10 05:45:04 -04:00
|
|
|
the (i-1)st dimension. Slicing in the first dimension would change
|
2007-04-09 01:51:32 -04:00
|
|
|
the location of the starting pointer directly (i.e. buf would
|
|
|
|
be modified).
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``itemsize``
|
2007-04-26 17:43:28 -04:00
|
|
|
This is a storage for the itemsize of each element of the shared
|
|
|
|
memory. It is strictly un-necessary as it can be obtained using
|
2007-04-27 02:58:33 -04:00
|
|
|
``PyBuffer_SizeFromFormat``, however an exporter may know this
|
2007-04-26 17:43:28 -04:00
|
|
|
information without parsing the format string and it is necessary
|
|
|
|
to know the itemsize for proper interpretation of striding.
|
|
|
|
Therefore, storing it is more convenient and faster.
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``internal``
|
2007-04-10 05:45:04 -04:00
|
|
|
This is for use internally by the exporting object. For example,
|
|
|
|
this might be re-cast as an integer by the exporter and used to
|
|
|
|
store flags about whether or not the shape, strides, and suboffsets
|
|
|
|
arrays must be freed when the buffer is released. The consumer
|
2007-04-26 17:43:28 -04:00
|
|
|
should never alter this value.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
The exporter is responsible for making sure that any memory pointed to
|
|
|
|
by buf, format, shape, strides, and suboffsets is valid until
|
2007-04-09 01:51:32 -04:00
|
|
|
releasebuffer is called. If the exporter wants to be able to change
|
2007-04-26 17:43:28 -04:00
|
|
|
an object's shape, strides, and/or suboffsets before releasebuffer is
|
|
|
|
called then it should allocate those arrays when getbuffer is called
|
|
|
|
(pointing to them in the buffer-info structure provided) and free them
|
|
|
|
when releasebuffer is called.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
|
2007-04-10 05:45:04 -04:00
|
|
|
The same bufferinfo struct should be used in the release-buffer
|
2007-04-09 01:51:32 -04:00
|
|
|
interface call. The caller is responsible for the memory of the
|
2007-04-10 05:45:04 -04:00
|
|
|
bufferinfo structure itself.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
``typedef int (*releasebufferproc)(PyObject *obj, PyBuffer *view)``
|
2007-04-09 01:51:32 -04:00
|
|
|
Callers of getbufferproc must make sure that this function is
|
|
|
|
called when memory previously acquired from the object is no
|
|
|
|
longer needed. The exporter of the interface must make sure that
|
|
|
|
any memory pointed to in the bufferinfo structure remains valid
|
|
|
|
until releasebuffer is called.
|
|
|
|
|
|
|
|
Both of these routines are optional for a type object
|
|
|
|
|
|
|
|
If the releasebuffer function is not provided then it does not ever
|
|
|
|
need to be called.
|
|
|
|
|
|
|
|
Exporters will need to define a releasebuffer function if they can
|
|
|
|
re-allocate their memory, strides, shape, suboffsets, or format
|
|
|
|
variables which they might share through the struct bufferinfo.
|
|
|
|
Several mechanisms could be used to keep track of how many getbuffer
|
|
|
|
calls have been made and shared. Either a single variable could be
|
|
|
|
used to keep track of how many "views" have been exported, or a
|
|
|
|
linked-list of bufferinfo structures filled in could be maintained in
|
2007-04-10 05:45:04 -04:00
|
|
|
each object.
|
|
|
|
|
|
|
|
All that is specifically required by the exporter, however, is to
|
|
|
|
ensure that any memory shared through the bufferinfo structure remains
|
2007-04-26 17:43:28 -04:00
|
|
|
valid until releasebuffer is called on the bufferinfo structure
|
|
|
|
exporting that memory.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
|
|
|
|
New C-API calls are proposed
|
|
|
|
============================
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
int PyObject_CheckBuffer(PyObject *obj)
|
|
|
|
|
|
|
|
Return 1 if the getbuffer function is available otherwise 0.
|
|
|
|
|
|
|
|
::
|
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
int PyObject_GetBuffer(PyObject *obj, PyBuffer *view,
|
|
|
|
int flags)
|
2007-04-10 05:45:04 -04:00
|
|
|
|
|
|
|
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
|
2007-04-26 17:43:28 -04:00
|
|
|
call. Returns -1 and raises an error on failure and returns 0 on
|
2007-04-27 02:58:33 -04:00
|
|
|
success.
|
|
|
|
|
|
|
|
::
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
int PyObject_ReleaseBuffer(PyObject *obj, PyBuffer *view)
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
This is a C-API version of the releasebuffer function call. It checks
|
|
|
|
to make sure the object has the required function pointer and issues
|
|
|
|
the call. Returns 0 on success and -1 (with an error raised) on
|
|
|
|
failure. This function always succeeds if there is no releasebuffer
|
|
|
|
function for the object.
|
2007-04-10 05:45:04 -04:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
PyObject *PyObject_GetMemoryView(PyObject *obj)
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
Return a memory-view object from an object that defines the buffer interface.
|
|
|
|
|
|
|
|
A memory-view object is an extended buffer object that could replace
|
|
|
|
the buffer object (but doesn't have to as that could be kept as a
|
2007-04-27 02:58:33 -04:00
|
|
|
simple 1-d memory-view object). Its C-structure is ::
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD
|
|
|
|
PyObject *base;
|
2007-04-26 17:43:28 -04:00
|
|
|
int ndims;
|
|
|
|
Py_ssize_t *starts; /* slice starts */
|
|
|
|
Py_ssize_t *stops; /* slice stops */
|
|
|
|
Py_ssize_t *steps; /* slice steps */
|
2007-04-09 01:51:32 -04:00
|
|
|
} PyMemoryViewObject;
|
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
This is functionally similar to the current buffer object except only
|
|
|
|
a reference to base is kept. The actual memory for base must be
|
|
|
|
re-grabbed using the buffer-protocol, whenever it is actually
|
|
|
|
needed (after which it is immediately released).
|
|
|
|
|
|
|
|
The getbuffer and releasebuffer for this object use the underlying
|
|
|
|
base object (adjusted as needed using the slice information). If the
|
|
|
|
number of dimensions of the base object (or the strides or the size)
|
|
|
|
has changed when a new view is requested, then the getbuffer will
|
|
|
|
trigger an error. Methods on the MemoryView object will allow
|
|
|
|
manual locking and unlocking of the underlying buffer.
|
|
|
|
|
|
|
|
This memory-view object will support mult-dimensional slicing and be
|
|
|
|
the first object provided with Python to do so. Slices of the
|
|
|
|
memory-view object are other memory-view objects. When an "element"
|
|
|
|
from the memory-view is returned it is always a bytes object whose
|
|
|
|
format should be interpreted by the format attribute of the memoryview
|
|
|
|
object. The struct module can be used to "decode" the bytes in Python
|
|
|
|
if desired.
|
|
|
|
|
|
|
|
The Python name will be
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
``__builtin__.memory``
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
Methods:
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
| ``lock``
|
|
|
|
| ``unlock``
|
|
|
|
| ``__getitem__`` (will support multi-dimensional slicing)
|
|
|
|
| ``__setitem__`` (will support multi-dimensional slicing)
|
|
|
|
| ``tobytes`` (obtain a bytes-object of everything in the memory).
|
|
|
|
| ``tolist`` (obtain a "nested" list of the memory. Everything
|
|
|
|
is interpreted into standard Python objects
|
|
|
|
as the struct module unpack would do).
|
2007-04-26 17:43:28 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
Attributes (taken from the memory of the base object):
|
2007-04-26 17:43:28 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
* ``format``
|
|
|
|
* ``itemsize``
|
|
|
|
* ``shape``
|
|
|
|
* ``strides``
|
|
|
|
* ``suboffsets``
|
|
|
|
* ``size``
|
|
|
|
* ``readonly``
|
|
|
|
* ``ndim``
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
|
|
|
|
::
|
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
int PyBuffer_SizeFromFormat(const char *)
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
Return the implied itemsize of the data-format area from a struct-style
|
|
|
|
description.
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
int PyObject_GetContiguous(PyObject *obj, void **buf, Py_ssize_t *len,
|
2007-04-26 17:43:28 -04:00
|
|
|
char **format, char fortran)
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
Return a contiguous chunk of memory representing the buffer. If a
|
|
|
|
copy is made then return 1. If no copy was needed return 0. If an
|
|
|
|
error occurred in probing the buffer interface, then return -1. The
|
|
|
|
contiguous chunk of memory is pointed to by ``*buf`` and the length of
|
|
|
|
that memory is ``*len``. If the object is multi-dimensional, then if
|
2007-04-26 17:43:28 -04:00
|
|
|
fortran is 'F', the first dimension of the underlying array will vary
|
|
|
|
the fastest in the buffer. If fortran is 'C', then the last dimension
|
|
|
|
will vary the fastest (C-style contiguous). If fortran is 'A', then it
|
2007-04-10 05:45:04 -04:00
|
|
|
does not matter and you will get whatever the object decides is more
|
2007-04-26 17:43:28 -04:00
|
|
|
efficient. If a copy is made, then the memory must be freed by calling
|
|
|
|
``PyMem_Free``.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
int PyObject_CopyToObject(PyObject *obj, void *buf, Py_ssize_t len,
|
2007-04-26 17:43:28 -04:00
|
|
|
char fortran)
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
Copy ``len`` bytes of data pointed to by the contiguous chunk of
|
|
|
|
memory pointed to by ``buf`` into the buffer exported by obj. Return
|
|
|
|
0 on success and return -1 and raise an error on failure. If the
|
|
|
|
object does not have a writeable buffer, then an error is raised. If
|
2007-04-26 17:43:28 -04:00
|
|
|
fortran is 'F', then if the object is multi-dimensional, then the data
|
2007-04-09 01:51:32 -04:00
|
|
|
will be copied into the array in Fortran-style (first dimension varies
|
2007-04-26 17:43:28 -04:00
|
|
|
the fastest). If fortran is 'C', then the data will be copied into the
|
|
|
|
array in C-style (last dimension varies the fastest). If fortran is 'A', then
|
2007-04-10 05:45:04 -04:00
|
|
|
it does not matter and the copy will be made in whatever way is more
|
|
|
|
efficient.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
These last three C-API calls allow a standard way of getting data in and
|
2007-04-09 01:51:32 -04:00
|
|
|
out of Python objects into contiguous memory areas no matter how it is
|
|
|
|
actually stored. These calls use the extended buffer interface to perform
|
|
|
|
their work.
|
|
|
|
|
|
|
|
::
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
int PyBuffer_IsContiguous(PyBuffer *view, char fortran)
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
Return 1 if the memory defined by the view object is C-style (fortran
|
|
|
|
= 'C') or Fortran-style (fortran = 'F') contiguous or either one
|
2007-04-27 02:58:33 -04:00
|
|
|
(fortran = 'A'). Return 0 otherwise.
|
|
|
|
|
|
|
|
::
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
int PyBuffer_IsAligned(PyBuffer *view)
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
Return 1 if the memory at all elements of the array implied by the
|
|
|
|
view object is aligned
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
::
|
|
|
|
|
|
|
|
void PyBuffer_FillContiguousStrides(int *ndims, Py_ssize_t *shape,
|
2007-04-09 01:51:32 -04:00
|
|
|
int itemsize,
|
2007-04-26 17:43:28 -04:00
|
|
|
Py_ssize_t *strides, char fortran)
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-10 05:45:04 -04:00
|
|
|
Fill the strides array with byte-strides of a contiguous (C-style if
|
|
|
|
fortran is 0 or Fortran-style if fortran is 1) array of the given
|
2007-04-27 02:58:33 -04:00
|
|
|
shape with the given number of bytes per element.
|
|
|
|
|
|
|
|
::
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
int PyBuffer_FillInfo(PyBuffer *view, void *buf,
|
|
|
|
Py_ssize_t len, int readonly, int infoflags)
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
Fills in a buffer-info structure correctly for an exporter that can
|
|
|
|
only share a contiguous chunk of memory of "unsigned bytes" of the
|
|
|
|
given length. Returns 0 on success and -1 (with raising an error) on
|
|
|
|
error.
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
::
|
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
PyErr_BufferError
|
|
|
|
|
|
|
|
A new error object for returning buffer errors which arise because an
|
|
|
|
exporter cannot provide the kind of buffer that a consumer expects.
|
|
|
|
This will also be raised when a consumer requests a buffer from an
|
|
|
|
object that does not provide the protocol.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
|
|
|
|
Additions to the struct string-syntax
|
|
|
|
=====================================
|
|
|
|
|
|
|
|
The struct string-syntax is missing some characters to fully
|
|
|
|
implement data-format descriptions already available elsewhere (in
|
|
|
|
ctypes and NumPy for example). The Python 2.5 specification is
|
2007-04-27 02:58:33 -04:00
|
|
|
at http://docs.python.org/lib/module-struct.html.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
Here are the proposed additions:
|
|
|
|
|
|
|
|
|
|
|
|
================ ===========
|
|
|
|
Character Description
|
|
|
|
================ ===========
|
|
|
|
't' bit (number before states how many bits)
|
|
|
|
'?' platform _Bool type
|
|
|
|
'g' long double
|
|
|
|
'c' ucs-1 (latin-1) encoding
|
|
|
|
'u' ucs-2
|
|
|
|
'w' ucs-4
|
|
|
|
'O' pointer to Python Object
|
|
|
|
'Z' complex (whatever the next specifier is)
|
|
|
|
'&' specific pointer (prefix before another charater)
|
|
|
|
'T{}' structure (detailed layout inside {})
|
|
|
|
'(k1,k2,...,kn)' multi-dimensional array of whatever follows
|
|
|
|
':name:' optional name of the preceeding element
|
|
|
|
'X{}' pointer to a function (optional function
|
|
|
|
signature inside {})
|
2007-05-25 14:04:40 -04:00
|
|
|
' ', '\\n', \\t' ignored (allow better readability)
|
2007-04-26 17:43:28 -04:00
|
|
|
-- this may already be true
|
2007-04-09 01:51:32 -04:00
|
|
|
================ ===========
|
|
|
|
|
|
|
|
The struct module will be changed to understand these as well and
|
2007-04-26 17:43:28 -04:00
|
|
|
return appropriate Python objects on unpacking. Unpacking a
|
2007-04-10 05:45:04 -04:00
|
|
|
long-double will return a decimal object or a ctypes long-double.
|
|
|
|
Unpacking 'u' or 'w' will return Python unicode. Unpacking a
|
2007-04-26 17:43:28 -04:00
|
|
|
multi-dimensional array will return a list (of lists if >1d).
|
|
|
|
Unpacking a pointer will return a ctypes pointer object. Unpacking a
|
|
|
|
function pointer will return a ctypes call-object (perhaps). Unpacking
|
|
|
|
a bit will return a Python Bool. White-space in the struct-string
|
|
|
|
syntax will be ignored if it isn't already. Unpacking a named-object
|
|
|
|
will return some kind of named-tuple-like object that acts like a
|
|
|
|
tuple but whose entries can also be accessed by name. Unpacking a
|
|
|
|
nested structure will return a nested tuple.
|
|
|
|
|
|
|
|
Endian-specification ('!', '@','=','>','<', '^') is also allowed
|
|
|
|
inside the string so that it can change if needed. The
|
|
|
|
previously-specified endian string is in force until changed. The
|
|
|
|
default endian is '@' which means native data-types and alignment. If
|
|
|
|
un-aligned, native data-types are requested, then the endian
|
2007-04-27 02:58:33 -04:00
|
|
|
specification is '^'.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
According to the struct-module, a number can preceed a character
|
|
|
|
code to specify how many of that type there are. The
|
2007-04-27 02:58:33 -04:00
|
|
|
``(k1,k2,...,kn)`` extension also allows specifying if the data is
|
2007-04-09 01:51:32 -04:00
|
|
|
supposed to be viewed as a (C-style contiguous, last-dimension
|
|
|
|
varies the fastest) multi-dimensional array of a particular format.
|
|
|
|
|
|
|
|
Functions should be added to ctypes to create a ctypes object from
|
|
|
|
a struct description, and add long-double, and ucs-2 to ctypes.
|
|
|
|
|
|
|
|
Examples of Data-Format Descriptions
|
|
|
|
====================================
|
|
|
|
|
|
|
|
Here are some examples of C-structures and how they would be
|
2007-04-26 17:43:28 -04:00
|
|
|
represented using the struct-style syntax.
|
|
|
|
|
|
|
|
<named> is the constructor for a named-tuple (not-specified yet).
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
float
|
2007-04-27 02:58:33 -04:00
|
|
|
``'f'`` <--> Python float
|
2007-04-09 01:51:32 -04:00
|
|
|
complex double
|
2007-04-27 02:58:33 -04:00
|
|
|
``'Zd'`` <--> Python complex
|
2007-04-09 01:51:32 -04:00
|
|
|
RGB Pixel data
|
2007-04-27 02:58:33 -04:00
|
|
|
``'BBB'`` <--> (int, int, int)
|
|
|
|
``'B:r: B:g: B:b:'`` <--> <named>((int, int, int), ('r','g','b'))
|
2007-04-26 17:43:28 -04:00
|
|
|
|
2007-04-09 01:51:32 -04:00
|
|
|
Mixed endian (weird but possible)
|
2007-04-27 02:58:33 -04:00
|
|
|
``'>i:big: <i:little:'`` <--> <named>((int, int), ('big', 'little'))
|
2007-04-26 17:43:28 -04:00
|
|
|
|
2007-04-09 01:51:32 -04:00
|
|
|
Nested structure
|
|
|
|
::
|
|
|
|
|
|
|
|
struct {
|
|
|
|
int ival;
|
|
|
|
struct {
|
|
|
|
unsigned short sval;
|
|
|
|
unsigned char bval;
|
|
|
|
unsigned char cval;
|
|
|
|
} sub;
|
|
|
|
}
|
2007-04-10 05:45:04 -04:00
|
|
|
"""i:ival:
|
|
|
|
T{
|
|
|
|
H:sval:
|
|
|
|
B:bval:
|
|
|
|
B:cval:
|
|
|
|
}:sub:
|
|
|
|
"""
|
2007-04-09 01:51:32 -04:00
|
|
|
Nested array
|
|
|
|
::
|
|
|
|
|
|
|
|
struct {
|
|
|
|
int ival;
|
|
|
|
double data[16*4];
|
|
|
|
}
|
2007-04-26 17:43:28 -04:00
|
|
|
"""i:ival:
|
|
|
|
(16,4)d:data:
|
|
|
|
"""
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-09 01:51:32 -04:00
|
|
|
Code to be affected
|
|
|
|
===================
|
|
|
|
|
|
|
|
All objects and modules in Python that export or consume the old
|
|
|
|
buffer interface will be modified. Here is a partial list.
|
|
|
|
|
|
|
|
* buffer object
|
|
|
|
* bytes object
|
|
|
|
* string object
|
|
|
|
* array module
|
|
|
|
* struct module
|
|
|
|
* mmap module
|
|
|
|
* ctypes module
|
|
|
|
|
|
|
|
Anything else using the buffer API.
|
|
|
|
|
|
|
|
|
|
|
|
Issues and Details
|
|
|
|
==================
|
|
|
|
|
2007-04-10 05:45:04 -04:00
|
|
|
It is intended that this PEP will be back-ported to Python 2.6 by
|
|
|
|
adding the C-API and the two functions to the existing buffer
|
|
|
|
protocol.
|
|
|
|
|
2007-04-09 01:51:32 -04:00
|
|
|
The proposed locking mechanism relies entirely on the exporter object
|
|
|
|
to not invalidate any of the memory pointed to by the buffer structure
|
|
|
|
until a corresponding releasebuffer is called. If it wants to be able
|
|
|
|
to change its own shape and/or strides arrays, then it needs to create
|
|
|
|
memory for these in the bufferinfo structure and copy information
|
|
|
|
over.
|
|
|
|
|
|
|
|
The sharing of strided memory and suboffsets is new and can be seen as
|
|
|
|
a modification of the multiple-segment interface. It is motivated by
|
|
|
|
NumPy and the PIL. NumPy objects should be able to share their
|
|
|
|
strided memory with code that understands how to manage strided memory
|
|
|
|
because strided memory is very common when interfacing with compute
|
|
|
|
libraries.
|
|
|
|
|
2007-04-10 05:45:04 -04:00
|
|
|
Also, with this approach it should be possible to write generic code
|
2007-04-09 01:51:32 -04:00
|
|
|
that works with both kinds of memory.
|
|
|
|
|
|
|
|
Memory management of the format string, the shape array, the strides
|
|
|
|
array, and the suboffsets array in the bufferinfo structure is always
|
|
|
|
the responsibility of the exporting object. The consumer should not
|
|
|
|
set these pointers to any other memory or try to free them.
|
|
|
|
|
2007-04-10 05:45:04 -04:00
|
|
|
Several ideas were discussed and rejected:
|
|
|
|
|
|
|
|
Having a "releaser" object whose release-buffer was called. This
|
|
|
|
was deemed unacceptable because it caused the protocol to be
|
|
|
|
asymmetric (you called release on something different than you
|
|
|
|
"got" the buffer from). It also complicated the protocol without
|
|
|
|
providing a real benefit.
|
|
|
|
|
|
|
|
Passing all the struct variables separately into the function.
|
|
|
|
This had the advantage that it allowed one to set NULL to
|
|
|
|
variables that were not of interest, but it also made the function
|
|
|
|
call more difficult. The flags variable allows the same
|
|
|
|
ability of consumers to be "simple" in how they call the protocol.
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
|
2007-04-09 01:51:32 -04:00
|
|
|
Code
|
2007-04-27 02:58:33 -04:00
|
|
|
====
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
The authors of the PEP promise to contribute and maintain the code for
|
|
|
|
this proposal but will welcome any help.
|
|
|
|
|
|
|
|
|
2007-04-10 05:45:04 -04:00
|
|
|
|
|
|
|
|
2007-04-09 01:51:32 -04:00
|
|
|
Examples
|
2007-04-27 02:58:33 -04:00
|
|
|
========
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
Ex. 1
|
2007-04-26 17:43:28 -04:00
|
|
|
-----------
|
2007-04-09 01:51:32 -04:00
|
|
|
|
2007-04-27 01:52:31 -04:00
|
|
|
This example shows how an image object that uses contiguous lines might expose its buffer::
|
2007-04-26 17:43:28 -04:00
|
|
|
|
2007-04-09 01:51:32 -04:00
|
|
|
struct rgba {
|
|
|
|
unsigned char r, g, b, a;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ImageObject {
|
|
|
|
PyObject_HEAD;
|
|
|
|
...
|
|
|
|
struct rgba** lines;
|
|
|
|
Py_ssize_t height;
|
|
|
|
Py_ssize_t width;
|
|
|
|
Py_ssize_t shape_array[2];
|
|
|
|
Py_ssize_t stride_array[2];
|
|
|
|
Py_ssize_t view_count;
|
|
|
|
};
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
"lines" points to malloced 1-D array of ``(struct rgba*)``. Each pointer
|
|
|
|
in THAT block points to a seperately malloced array of ``(struct rgba)``.
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
In order to access, say, the red value of the pixel at x=30, y=50, you'd use "lines[50][30].r".
|
|
|
|
|
|
|
|
So what does ImageObject's getbuffer do? Leaving error checking out::
|
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
int Image_getbuffer(PyObject *self, PyBuffer *view, int flags) {
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
static Py_ssize_t suboffsets[2] = { -1, 0 };
|
|
|
|
|
|
|
|
view->buf = self->lines;
|
|
|
|
view->len = self->height*self->width;
|
|
|
|
view->readonly = 0;
|
|
|
|
view->ndims = 2;
|
|
|
|
self->shape_array[0] = height;
|
|
|
|
self->shape_array[1] = width;
|
|
|
|
view->shape = &self->shape_array;
|
|
|
|
self->stride_array[0] = sizeof(struct rgba*);
|
|
|
|
self->stride_array[1] = sizeof(struct rgba);
|
|
|
|
view->strides = &self->stride_array;
|
|
|
|
view->suboffsets = suboffsets;
|
|
|
|
|
|
|
|
self->view_count ++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
int Image_releasebuffer(PyObject *self, PyBuffer *view) {
|
2007-04-09 01:51:32 -04:00
|
|
|
self->view_count--;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-10 05:45:04 -04:00
|
|
|
Ex. 2
|
|
|
|
-----------
|
|
|
|
|
|
|
|
This example shows how an object that wants to expose a contiguous
|
|
|
|
chunk of memory (which will never be re-allocated while the object is
|
2007-04-26 17:43:28 -04:00
|
|
|
alive) would do that.
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
::
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
int myobject_getbuffer(PyObject *self, PyBuffer *view, int flags) {
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
void *buf;
|
|
|
|
Py_ssize_t len;
|
|
|
|
int readonly=0;
|
|
|
|
|
|
|
|
buf = /* Point to buffer */
|
|
|
|
len = /* Set to size of buffer */
|
|
|
|
readonly = /* Set to 1 if readonly */
|
|
|
|
|
|
|
|
return PyObject_FillBufferInfo(view, buf, len, readonly, flags);
|
2007-04-10 05:45:04 -04:00
|
|
|
}
|
|
|
|
|
2007-04-27 01:52:31 -04:00
|
|
|
/* No releasebuffer is necessary because the memory will never
|
|
|
|
be re-allocated so the locking mechanism is not needed
|
|
|
|
*/
|
2007-04-10 05:45:04 -04:00
|
|
|
|
|
|
|
Ex. 3
|
|
|
|
-----------
|
|
|
|
|
|
|
|
A consumer that wants to only get a simple contiguous chunk of bytes
|
2007-04-26 17:43:28 -04:00
|
|
|
from a Python object, obj would do the following:
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
::
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
PyBuffer view;
|
2007-04-10 05:45:04 -04:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (PyObject_GetBuffer(obj, &view, Py_BUF_SIMPLE) < 0) {
|
|
|
|
/* error return */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now, view.buf is the pointer to memory
|
|
|
|
view.len is the length
|
|
|
|
view.readonly is whether or not the memory is read-only.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* After using the information and you don't need it anymore */
|
|
|
|
|
|
|
|
if (PyObject_ReleaseBuffer(obj, &view) < 0) {
|
|
|
|
/* error return */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
Ex. 4
|
|
|
|
-----------
|
|
|
|
|
|
|
|
A consumer that wants to be able to use any object's memory but is
|
|
|
|
writing an algorithm that only handle contiguous memory could do the following:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
void *buf;
|
|
|
|
Py_ssize_t len;
|
|
|
|
char *format;
|
|
|
|
|
|
|
|
if (PyObject_GetContiguous(obj, &buf, &len, &format, 0) < 0) {
|
|
|
|
/* error return */
|
|
|
|
}
|
2007-04-10 05:45:04 -04:00
|
|
|
|
2007-04-26 17:43:28 -04:00
|
|
|
/* process memory pointed to by buffer if format is correct */
|
|
|
|
|
|
|
|
/* Optional:
|
|
|
|
|
|
|
|
if, after processing, we want to copy data from buffer back
|
2007-04-27 20:36:48 -04:00
|
|
|
into the object
|
2007-04-26 17:43:28 -04:00
|
|
|
|
|
|
|
we could do
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (PyObject_CopyToObject(obj, buf, len, 0) < 0) {
|
|
|
|
/* error return */
|
|
|
|
}
|
|
|
|
|
2007-04-09 01:51:32 -04:00
|
|
|
|
|
|
|
Copyright
|
|
|
|
=========
|
|
|
|
|
2007-04-27 02:58:33 -04:00
|
|
|
This PEP is placed in the public domain.
|
2007-04-09 01:51:32 -04:00
|
|
|
|