(buffer Protocol)

Python buffer bytes bytearray array.array

Python buffer protocol C :

bytes bytearray array.array

buffer write() : buffer write() readinto() buffer

buffer:

buffer PyBuffer_Release()

buffer

"buffers"PythonPythonC

Python PyObject C memoryview

Buffer Object Structures PyObject_GetBuffer()

Py_buffer
void *buf

strides

void *obj

PyBuffer_Release() NULL C-API

PyMemoryView_FromBuffer() PyBuffer_FillInfo() NULL

Py_ssize_t len

product(shape) * itemsizecontiguouscontiguous contiguous

((char *)buf)[0] ((char *)buf)[len-1] (contiguity) PyBUF_SIMPLE PyBUF_WRITABLE

int readonly

PyBUF_WRITABLE

Py_ssize_t itemsize

byte struct.calcsize() NULL format

: PyBUF_FORMAT format NULL itemsize

shape product(shape) * itemsize == len itemsize buffer

PyBUF_SIMPLE PyBUF_WRITABLE shape NULL itemsize itemsize == 1

const char *format

struct NUL NULL "B" ()

PyBUF_FORMAT

int ndim

N 0 buf 1 shape, strides, suboffsets NULL

PyBUF_MAX_NDIM 64 PyBUF_MAX_NDIM

Py_ssize_t *shape

N ndim Py_ssize_t shape[0] * ... * shape[ndim-1] * itemsize len

shape shape[n] >= 0 shape[n] == 0 complex arrays

shepe ()

Py_ssize_t *strides

ndim Py_ssize_t

strides[n] <= 0 complex arrays

strides

Py_ssize_t *suboffsets

Py_ssize_t ndim suboffsets[n] >= 0 n suboffset suboffset ()

suboffset () NULL ()

Python Imaging Library (PIL) complex arrays

suboffsets

void *internal

shape, strides, suboffsets

PyObject_GetBuffer() flags

Py_buffer

flags : obj, buf, len, itemsize, ndim.

readonly, format

PyBUF_WRITABLE

readonly exporter exporter

PyBUF_FORMAT

format NULL

PyBUF_WRITABLE | PyBUF_SIMPLE 0 PyBUF_WRITABLE

PyBUF_FORMAT PyBUF_SIMPLE | B ()

shape, strides, suboffsets

shape strides suboffsets
PyBUF_INDIRECT
yes yes
PyBUF_STRIDES
yes yes NULL
PyBUF_ND
yes NULL NULL
PyBUF_SIMPLE
NULL NULL NULL

C Fortran C

shape strides suboffsets contig
PyBUF_C_CONTIGUOUS
yes yes NULL C
PyBUF_F_CONTIGUOUS
yes yes NULL F
PyBUF_ANY_CONTIGUOUS
yes yes NULL C F
PyBUF_ND
yes NULL NULL C

U PyBuffer_IsContiguous()

shape strides suboffsets contig readonly format
PyBUF_FULL
yes yes U 0 yes
PyBUF_FULL_RO
yes yes U 1 0 yes
PyBUF_RECORDS
yes yes NULL U 0 yes
PyBUF_RECORDS_RO
yes yes NULL U 1 0 yes
PyBUF_STRIDED
yes yes NULL U 0 NULL
PyBUF_STRIDED_RO
yes yes NULL U 1 0 NULL
PyBUF_CONTIG
yes NULL NULL C 0 NULL
PyBUF_CONTIG_RO
yes NULL NULL C 1 0 NULL

NumPy : shape, strides

NumPy itemsize, ndim, shape, strides

ndim == 0 buf itemsize shape strides NULL

strides NULL n C n :

ptr = (char *)buf + indices[0] * strides[0] + ... + indices[n-1] * strides[n-1] item = *((typeof(item) *)ptr);

buf

def verify_structure(memlen, itemsize, ndim, shape, strides, offset):
    """Verify that the parameters represent a valid array within
       the bounds of the allocated memory:
           char *mem: start of the physical memory block
           memlen: length of the physical memory block
           offset: (char *)buf - mem
    """
    if offset % itemsize:
        return False
    if offset < 0 or offset+itemsize > memlen:
        return False
    if any(v % itemsize for v in strides):
        return False

    if ndim <= 0:
        return ndim == 0 and not shape and not strides
    if 0 in shape:
        return True

    imin = sum(strides[j]*(shape[j]-1) for j in range(ndim)
               if strides[j] <= 0)
    imax = sum(strides[j]*(shape[j]-1) for j in range(ndim)
               if strides[j] > 0)

    return 0 <= offset+imin and offset+imax+itemsize <= memlen

PIL : shape, strides, suboffsets

PIL 3 C char v[2][2][3] 2 2 char (*v[2])[2][3] suboffset 2 buf 2 char x[2][3]

strides suboffsets NULL N N

void *get_item_pointer(int ndim, void *buf, Py_ssize_t *strides,
                       Py_ssize_t *suboffsets, Py_ssize_t *indices) {
    char *pointer = (char*)buf;
    int i;
    for (i = 0; i < ndim; i++) {
        pointer += strides[i] * indices[i];
        if (suboffsets[i] >=0 ) {
            pointer = *((char**)pointer) + suboffsets[i];
        }
    }
    return (void*)pointer;
}