diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst index 230c6a9..fe5b2b0 100644 --- a/Doc/c-api/buffer.rst +++ b/Doc/c-api/buffer.rst @@ -137,12 +137,11 @@ a buffer, see :c:func:`PyObject_GetBuffer`. be set to *NULL*, but :c:member:`~Py_buffer.itemsize` still has the value for the original format. - If :c:member:`~Py_Buffer.shape` is present, the equality + If :c:macro:`PyBUF_ND` was specified, the equality ``product(shape) * itemsize == len`` still holds and the consumer can use :c:member:`~Py_buffer.itemsize` to navigate the buffer. - If :c:member:`~Py_Buffer.shape` is *NULL* as a result of a :c:macro:`PyBUF_SIMPLE` - or a :c:macro:`PyBUF_WRITABLE` request, the consumer must disregard + If :c:macro:`PyBUF_ND` was not specified, the consumer must disregard :c:member:`~Py_buffer.itemsize` and assume ``itemsize == 1``. .. c:member:: const char \*format @@ -260,22 +259,206 @@ shape, strides, suboffsets ~~~~~~~~~~~~~~~~~~~~~~~~~~ The flags that control the logical structure of the memory are listed -in decreasing order of complexity. Note that each flag contains all bits -of the flags below it. +here in increasing order of complexity. Note that each flag contains +all bits of the flags above it. + + .. c:macro:: PyBUF_SIMPLE + + Equivalent to no flags set. + + .. c:macro:: PyBUF_ND + + If specified, the consumer wants the + :c:member:`~Py_buffer.shape` field populated with information + describing the *shape* of the buffer (the number of elements in + each dimension). + + *Requirements for the Producer* + + If ``(flags & PyBUF_ND)`` is true: + + If ``(flags & PyBUF_STRIDES)`` is false *and* the producer + is unable to provide a block of memory of size + :c:member:`~Py_buffer.len` at :c:member:`~Py_buffer.buf` + containing all ``(len/itemsize)`` entries in a C-style + contiguous chunk, then the producer MUST raise + :c:data:`PyExc_BufferError`. + + Otherwise, the producer must provide the shape of the + buffer via the :c:member:`~Py_buffer.shape` field. + + If ``(flags & PyBUF_ND)`` is false: + + If the producer is unable to provide a block of memory of + size :c:member:`~Py_buffer.len` at + :c:member:`~Py_buffer.buf` containing all of the buffer's + data, then the producer MUST raise + :c:data:`PyExc_BufferError`. + + Otherwise, the producer is permitted to do any of the + following: + + * leave the :c:member:`~Py_buffer.shape` field alone + (don't set it to *NULL* or any other value) + * set the :c:member:`~Py_buffer.shape` field to *NULL* + * set the :c:member:`~Py_buffer.shape` field to point to + an array describing the shape + * set the :c:member:`~Py_buffer.shape` field to point to + any other location, even if dereferencing the pointer + would result in undefined behavior + + *Requirements for the Consumer* + + The consumer MUST NOT change the :c:member:`~Py_buffer.shape` + field. + + If ``(flags & PyBUF_ND)`` is true: + + The consumer MUST NOT modify the entries in the + :c:member:`~Py_buffer.shape` array. + + If ``(flags & PyBUF_ND)`` is false: + + The consumer MUST disregard + :c:member:`~Py_buffer.itemsize` and assume ``itemsize == + 1``. + + The consumer MUST ignore the :c:member:`~Py_buffer.shape` + field in the returned :c:data:`Py_buffer` structure, as it + may have any arbitrary value. In particular, it MUST NOT + dereference the :c:member:`~Py_buffer.shape` field. + + .. c:macro:: PyBUF_STRIDES + + If specified, the consumer wants the + :c:member:`~Py_buffer.strides` field populated with the *stride* + information for the buffer (for each dimension, the value that + must be added to a pointer to reach the next element in that + dimension). + + *Requirements for the Producer* + + If ``(flags & PyBUF_STRIDES)`` is true: + + The producer must provide the appropriate strides + information via the :c:member:`~Py_buffer.strides` field. + + If ``(flags & PyBUF_STRIDES)`` is false: + + If the producer is unable to provide a block of memory of + size :c:member:`~Py_buffer.len` at + :c:member:`~Py_buffer.buf` containing all of the buffer's + data, then the producer MUST raise + :c:data:`PyExc_BufferError`. + + Otherwise, the producer is permitted to do any of the + following: + + * leave the :c:member:`~Py_buffer.strides` field alone + (don't set it to *NULL* or any other value) + * set the :c:member:`~Py_buffer.strides` field to *NULL* + * set the :c:member:`~Py_buffer.strides` field to point to + an array describing the strides + * set the :c:member:`~Py_buffer.strides` field to point to + any other location, even if dereferencing the pointer + would result in undefined behavior + + *Requirements for the Consumer* + + The consumer MUST NOT change the + :c:member:`~Py_buffer.strides` field. + + If ``(flags & PyBUF_STRIDES)`` is true: + + The consumer MUST NOT modify the entries in the + :c:member:`~Py_buffer.strides` array. + + If ``(flags & PyBUF_STRIDES)`` is false: + + The consumer MUST ignore the + :c:member:`~Py_buffer.strides` field in the returned + :c:data:`Py_buffer` structure, as it may have any + arbitrary value. In particular, it MUST NOT dereference + the :c:member:`~Py_buffer.strides` field. + + .. c:macro:: PyBUF_INDIRECT + + If specified, the consumer wants the + :c:member:`~Py_buffer.suboffsets` field populated with + information used to dereference indirections (pointers) + contained in the buffer. + + *Requirements for the Producer* + + If ``(flags & PyBUF_INDIRECT)`` is true: + + If the buffer uses indirections then the producer MUST set + the :c:member:`~Py_buffer.suboffsets` field to point to an + array with appropriate entries. + + Otherwise, the producer MUST either set the + :c:member:`~Py_buffer.suboffsets` field to *NULL* or set + it to point to an array of all negative entries. + + If ``(flags & PyBUF_INDIRECT)`` is false: + + If the producer cannot produce a buffer that does not have + indirections, then the producer MUST raise + :c:data:`PyExc_BufferError`. + + Otherwise, the producer is permitted to do any of the + following: + + * leave the :c:member:`~Py_buffer.suboffsets` field alone + (don't set it to *NULL* or any other value) + * set the :c:member:`~Py_buffer.suboffsets` field to + *NULL* + * set the :c:member:`~Py_buffer.suboffsets` field to point + to an array describing the suboffsets + * set the :c:member:`~Py_buffer.suboffsets` field to point + to any other location, even if dereferencing the pointer + would result in undefined behavior + + *Requirements for the Consumer* + + The consumer MUST NOT change the + :c:member:`~Py_buffer.suboffsets` field. + + If ``(flags & PyBUF_INDIRECT)`` is true: + + The consumer MUST NOT modify the entries in the + :c:member:`~Py_buffer.suboffsets` array (assuming it is + non-*NULL*). + + If the :c:member:`~Py_buffer.suboffsets` field is not + *NULL* and each member of the array is negative, the + consumer MUST treat it as if the + :c:member:`~Py_buffer.suboffsets` field was *NULL*. + + If ``(flags & PyBUF_INDIRECT)`` is false: + + The consumer MUST ignore the + :c:member:`~Py_buffer.suboffsets` field in the returned + :c:data:`Py_buffer` structure, as it may have any + arbitrary value. In particular, it MUST NOT dereference + the :c:member:`~Py_buffer.suboffsets` field. + +The following table summarizes the behavior of the above flags (when +:c:member:`~Py_buffer.ndim` is greater than 0): .. tabularcolumns:: |p{0.35\linewidth}|l|l|l| -+-----------------------------+-------+---------+------------+ -| Request | shape | strides | suboffsets | -+=============================+=======+=========+============+ -| .. c:macro:: PyBUF_INDIRECT | yes | yes | if needed | -+-----------------------------+-------+---------+------------+ -| .. c:macro:: PyBUF_STRIDES | yes | yes | NULL | -+-----------------------------+-------+---------+------------+ -| .. c:macro:: PyBUF_ND | yes | NULL | NULL | -+-----------------------------+-------+---------+------------+ -| .. c:macro:: PyBUF_SIMPLE | NULL | NULL | NULL | -+-----------------------------+-------+---------+------------+ ++---------------------------+-------------+-------------+---------------+ +| Request | shape | strides | suboffsets | ++===========================+=============+=============+===============+ +| :c:macro:`PyBUF_INDIRECT` | yes | yes | yes or *NULL* | ++---------------------------+-------------+-------------+---------------+ +| :c:macro:`PyBUF_STRIDES` | yes | yes | unspecified | ++---------------------------+-------------+-------------+---------------+ +| :c:macro:`PyBUF_ND` | yes | unspecified | unspecified | ++---------------------------+-------------+-------------+---------------+ +| :c:macro:`PyBUF_SIMPLE` | unspecified | unspecified | unspecified | ++---------------------------+-------------+-------------+---------------+ contiguity requests @@ -286,17 +469,17 @@ information. Without stride information, the buffer must be C-contiguous. .. tabularcolumns:: |p{0.35\linewidth}|l|l|l|l| -+-----------------------------------+-------+---------+------------+--------+ -| Request | shape | strides | suboffsets | contig | -+===================================+=======+=========+============+========+ -| .. c:macro:: PyBUF_C_CONTIGUOUS | yes | yes | NULL | C | -+-----------------------------------+-------+---------+------------+--------+ -| .. c:macro:: PyBUF_F_CONTIGUOUS | yes | yes | NULL | F | -+-----------------------------------+-------+---------+------------+--------+ -| .. c:macro:: PyBUF_ANY_CONTIGUOUS | yes | yes | NULL | C or F | -+-----------------------------------+-------+---------+------------+--------+ -| .. c:macro:: PyBUF_ND | yes | NULL | NULL | C | -+-----------------------------------+-------+---------+------------+--------+ ++-----------------------------------+-------+-------------+-------------+--------+ +| Request | shape | strides | suboffsets | contig | ++===================================+=======+=============+=============+========+ +| .. c:macro:: PyBUF_C_CONTIGUOUS | yes | yes | unspecified | C | ++-----------------------------------+-------+-------------+-------------+--------+ +| .. c:macro:: PyBUF_F_CONTIGUOUS | yes | yes | unspecified | F | ++-----------------------------------+-------+-------------+-------------+--------+ +| .. c:macro:: PyBUF_ANY_CONTIGUOUS | yes | yes | unspecified | C or F | ++-----------------------------------+-------+-------------+-------------+--------+ +| .. c:macro:: PyBUF_ND | yes | unspecified | unspecified | C | ++-----------------------------------+-------+-------------+-------------+--------+ compound requests @@ -311,25 +494,25 @@ have to call :c:func:`PyBuffer_IsContiguous` to determine contiguity. .. tabularcolumns:: |p{0.35\linewidth}|l|l|l|l|l|l| -+-------------------------------+-------+---------+------------+--------+----------+--------+ -| Request | shape | strides | suboffsets | contig | readonly | format | -+===============================+=======+=========+============+========+==========+========+ -| .. c:macro:: PyBUF_FULL | yes | yes | if needed | U | 0 | yes | -+-------------------------------+-------+---------+------------+--------+----------+--------+ -| .. c:macro:: PyBUF_FULL_RO | yes | yes | if needed | U | 1 or 0 | yes | -+-------------------------------+-------+---------+------------+--------+----------+--------+ -| .. c:macro:: PyBUF_RECORDS | yes | yes | NULL | U | 0 | yes | -+-------------------------------+-------+---------+------------+--------+----------+--------+ -| .. c:macro:: PyBUF_RECORDS_RO | yes | yes | NULL | U | 1 or 0 | yes | -+-------------------------------+-------+---------+------------+--------+----------+--------+ -| .. c:macro:: PyBUF_STRIDED | yes | yes | NULL | U | 0 | NULL | -+-------------------------------+-------+---------+------------+--------+----------+--------+ -| .. c:macro:: PyBUF_STRIDED_RO | yes | yes | NULL | U | 1 or 0 | NULL | -+-------------------------------+-------+---------+------------+--------+----------+--------+ -| .. c:macro:: PyBUF_CONTIG | yes | NULL | NULL | C | 0 | NULL | -+-------------------------------+-------+---------+------------+--------+----------+--------+ -| .. c:macro:: PyBUF_CONTIG_RO | yes | NULL | NULL | C | 1 or 0 | NULL | -+-------------------------------+-------+---------+------------+--------+----------+--------+ ++-------------------------------+-------+-------------+---------------+--------+----------+--------+ +| Request | shape | strides | suboffsets | contig | readonly | format | ++===============================+=======+=============+===============+========+==========+========+ +| .. c:macro:: PyBUF_FULL | yes | yes | yes or *NULL* | U | 0 | yes | ++-------------------------------+-------+-------------+---------------+--------+----------+--------+ +| .. c:macro:: PyBUF_FULL_RO | yes | yes | yes or *NULL* | U | 1 or 0 | yes | ++-------------------------------+-------+-------------+---------------+--------+----------+--------+ +| .. c:macro:: PyBUF_RECORDS | yes | yes | unspecified | U | 0 | yes | ++-------------------------------+-------+-------------+---------------+--------+----------+--------+ +| .. c:macro:: PyBUF_RECORDS_RO | yes | yes | unspecified | U | 1 or 0 | yes | ++-------------------------------+-------+-------------+---------------+--------+----------+--------+ +| .. c:macro:: PyBUF_STRIDED | yes | yes | unspecified | U | 0 | NULL | ++-------------------------------+-------+-------------+---------------+--------+----------+--------+ +| .. c:macro:: PyBUF_STRIDED_RO | yes | yes | unspecified | U | 1 or 0 | NULL | ++-------------------------------+-------+-------------+---------------+--------+----------+--------+ +| .. c:macro:: PyBUF_CONTIG | yes | unspecified | unspecified | C | 0 | NULL | ++-------------------------------+-------+-------------+---------------+--------+----------+--------+ +| .. c:macro:: PyBUF_CONTIG_RO | yes | unspecified | unspecified | C | 1 or 0 | NULL | ++-------------------------------+-------+-------------+---------------+--------+----------+--------+ Complex arrays @@ -345,7 +528,7 @@ If ``ndim == 0``, the memory location pointed to by :c:member:`~Py_buffer.buf` i interpreted as a scalar of size :c:member:`~Py_buffer.itemsize`. In that case, both :c:member:`~Py_buffer.shape` and :c:member:`~Py_buffer.strides` are *NULL*. -If :c:member:`~Py_buffer.strides` is *NULL*, the array is interpreted as +If :c:macro:`PyBUF_STRIDES` was not specified, the array is interpreted as a standard n-dimensional C-array. Otherwise, the consumer must access an n-dimensional array as follows: