From ba9942e68cf64e5bc0b416fd41fb127063e1413a Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 18 Oct 2021 16:54:54 +0200 Subject: [PATCH 1/6] bpo-45459: Add Py_buffer to limited API --- Misc/NEWS.d/next/C API/2021-10-18-16-54-24.bpo-45459.Y1pEZs.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/C API/2021-10-18-16-54-24.bpo-45459.Y1pEZs.rst diff --git a/Misc/NEWS.d/next/C API/2021-10-18-16-54-24.bpo-45459.Y1pEZs.rst b/Misc/NEWS.d/next/C API/2021-10-18-16-54-24.bpo-45459.Y1pEZs.rst new file mode 100644 index 00000000000000..2da4d93f9bdea0 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2021-10-18-16-54-24.bpo-45459.Y1pEZs.rst @@ -0,0 +1 @@ +Add :c:type:`Py_buffer` to limited API / stable ABI. From e912267658b7aabbf941ccaad82e6564fb7c1cb0 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 18 Oct 2021 16:39:59 +0200 Subject: [PATCH 2/6] Move Py_buffer APIs to buffer.h --- Include/Python.h | 1 + Include/buffer.h | 120 +++++++++++++++++++++++++++++++++++++ Include/cpython/abstract.h | 68 --------------------- Include/cpython/object.h | 34 +---------- Include/typeslots.h | 6 -- Makefile.pre.in | 1 + 6 files changed, 123 insertions(+), 107 deletions(-) create mode 100644 Include/buffer.h diff --git a/Include/Python.h b/Include/Python.h index c0a621ad44afd1..f2b503e35cdfb9 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -48,6 +48,7 @@ #include "longobject.h" #include "cpython/longintrepr.h" #include "boolobject.h" +#include "buffer.h" #include "floatobject.h" #include "complexobject.h" #include "rangeobject.h" diff --git a/Include/buffer.h b/Include/buffer.h new file mode 100644 index 00000000000000..ee42024f451b6b --- /dev/null +++ b/Include/buffer.h @@ -0,0 +1,120 @@ +/* Public Py_buffer API */ + +#ifndef Py_BUFFER_H +#define Py_BUFFER_H +#ifdef __cplusplus +extern "C" { +#endif + +/* === New Buffer API ============================================ + * Limited API since Python 3.11 + */ + +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030b0000 + +typedef struct bufferinfo Py_buffer; + +/* Return 1 if the getbuffer function is available, otherwise return 0. */ +PyAPI_FUNC(int) PyObject_CheckBuffer(PyObject *obj); + +/* 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 + call. + + Returns -1 and raises an error on failure and returns 0 on success. */ +PyAPI_FUNC(int) PyObject_GetBuffer(PyObject *obj, Py_buffer *view, + int flags); + +/* Get the memory area pointed to by the indices for the buffer given. + Note that view->ndim is the assumed size of indices. */ +PyAPI_FUNC(void *) PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices); + +/* Return the implied itemsize of the data-format area from a + struct-style description. */ +PyAPI_FUNC(Py_ssize_t) PyBuffer_SizeFromFormat(const char *format); + +/* Implementation in memoryobject.c */ +PyAPI_FUNC(int) PyBuffer_ToContiguous(void *buf, Py_buffer *view, + Py_ssize_t len, char order); + +PyAPI_FUNC(int) PyBuffer_FromContiguous(Py_buffer *view, void *buf, + Py_ssize_t len, char order); + +/* Copy len bytes of data from the contiguous chunk of memory + pointed to by buf into the buffer exported by obj. Return + 0 on success and return -1 and raise a PyBuffer_Error on + error (i.e. the object does not have a buffer interface or + it is not working). + + If fort is 'F', then if the object is multi-dimensional, + then the data will be copied into the array in + Fortran-style (first dimension varies the fastest). If + fort is 'C', then the data will be copied into the array + in C-style (last dimension varies the fastest). If fort + is 'A', then it does not matter and the copy will be made + in whatever way is more efficient. */ +PyAPI_FUNC(int) PyObject_CopyData(PyObject *dest, PyObject *src); + +/* Copy the data from the src buffer to the buffer of destination. */ +PyAPI_FUNC(int) PyBuffer_IsContiguous(const Py_buffer *view, char fort); + +/*Fill the strides array with byte-strides of a contiguous + (Fortran-style if fort is 'F' or C-style otherwise) + array of the given shape with the given number of bytes + per element. */ +PyAPI_FUNC(void) PyBuffer_FillContiguousStrides(int ndims, + Py_ssize_t *shape, + Py_ssize_t *strides, + int itemsize, + char fort); + +/* 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. */ +PyAPI_FUNC(int) PyBuffer_FillInfo(Py_buffer *view, PyObject *o, void *buf, + Py_ssize_t len, int readonly, + int flags); + +/* Releases a Py_buffer obtained from getbuffer ParseTuple's "s*". */ +PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view); + +/* Maximum number of dimensions */ +#define PyBUF_MAX_NDIM 64 + +/* Flags for getting buffers */ +#define PyBUF_SIMPLE 0 +#define PyBUF_WRITABLE 0x0001 +/* we used to include an E, backwards compatible alias */ +#define PyBUF_WRITEABLE PyBUF_WRITABLE +#define PyBUF_FORMAT 0x0004 +#define PyBUF_ND 0x0008 +#define PyBUF_STRIDES (0x0010 | PyBUF_ND) +#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) +#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) +#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) +#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) + +#define PyBUF_CONTIG (PyBUF_ND | PyBUF_WRITABLE) +#define PyBUF_CONTIG_RO (PyBUF_ND) + +#define PyBUF_STRIDED (PyBUF_STRIDES | PyBUF_WRITABLE) +#define PyBUF_STRIDED_RO (PyBUF_STRIDES) + +#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT) +#define PyBUF_RECORDS_RO (PyBUF_STRIDES | PyBUF_FORMAT) + +#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT) +#define PyBUF_FULL_RO (PyBUF_INDIRECT | PyBUF_FORMAT) + + +#define PyBUF_READ 0x100 +#define PyBUF_WRITE 0x200 + +#endif /* Py_LIMITED_API */ + +#ifdef __cplusplus +} +#endif +#endif /* Py_BUFFER_H */ \ No newline at end of file diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index 55a742c31fada0..b5a31392f2ed0e 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -168,74 +168,6 @@ PyAPI_FUNC(int) _PyObject_HasLen(PyObject *o); value. If one of the calls fails, this function returns -1. */ PyAPI_FUNC(Py_ssize_t) PyObject_LengthHint(PyObject *o, Py_ssize_t); -/* === New Buffer API ============================================ */ - -/* Return 1 if the getbuffer function is available, otherwise return 0. */ -PyAPI_FUNC(int) PyObject_CheckBuffer(PyObject *obj); - -/* 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 - call. - - Returns -1 and raises an error on failure and returns 0 on success. */ -PyAPI_FUNC(int) PyObject_GetBuffer(PyObject *obj, Py_buffer *view, - int flags); - -/* Get the memory area pointed to by the indices for the buffer given. - Note that view->ndim is the assumed size of indices. */ -PyAPI_FUNC(void *) PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices); - -/* Return the implied itemsize of the data-format area from a - struct-style description. */ -PyAPI_FUNC(Py_ssize_t) PyBuffer_SizeFromFormat(const char *format); - -/* Implementation in memoryobject.c */ -PyAPI_FUNC(int) PyBuffer_ToContiguous(void *buf, Py_buffer *view, - Py_ssize_t len, char order); - -PyAPI_FUNC(int) PyBuffer_FromContiguous(Py_buffer *view, void *buf, - Py_ssize_t len, char order); - -/* Copy len bytes of data from the contiguous chunk of memory - pointed to by buf into the buffer exported by obj. Return - 0 on success and return -1 and raise a PyBuffer_Error on - error (i.e. the object does not have a buffer interface or - it is not working). - - If fort is 'F', then if the object is multi-dimensional, - then the data will be copied into the array in - Fortran-style (first dimension varies the fastest). If - fort is 'C', then the data will be copied into the array - in C-style (last dimension varies the fastest). If fort - is 'A', then it does not matter and the copy will be made - in whatever way is more efficient. */ -PyAPI_FUNC(int) PyObject_CopyData(PyObject *dest, PyObject *src); - -/* Copy the data from the src buffer to the buffer of destination. */ -PyAPI_FUNC(int) PyBuffer_IsContiguous(const Py_buffer *view, char fort); - -/*Fill the strides array with byte-strides of a contiguous - (Fortran-style if fort is 'F' or C-style otherwise) - array of the given shape with the given number of bytes - per element. */ -PyAPI_FUNC(void) PyBuffer_FillContiguousStrides(int ndims, - Py_ssize_t *shape, - Py_ssize_t *strides, - int itemsize, - char fort); - -/* 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. */ -PyAPI_FUNC(int) PyBuffer_FillInfo(Py_buffer *view, PyObject *o, void *buf, - Py_ssize_t len, int readonly, - int flags); - -/* Releases a Py_buffer obtained from getbuffer ParseTuple's "s*". */ -PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view); - /* === Sequence protocol ================================================ */ /* Assume tp_as_sequence and sq_item exist and that 'i' does not diff --git a/Include/cpython/object.h b/Include/cpython/object.h index 849d5aa6a2c72a..4025a9640140c6 100644 --- a/Include/cpython/object.h +++ b/Include/cpython/object.h @@ -63,43 +63,11 @@ typedef struct bufferinfo { typedef int (*getbufferproc)(PyObject *, Py_buffer *, int); typedef void (*releasebufferproc)(PyObject *, Py_buffer *); +/* End buffer interface */ typedef PyObject *(*vectorcallfunc)(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames); -/* Maximum number of dimensions */ -#define PyBUF_MAX_NDIM 64 - -/* Flags for getting buffers */ -#define PyBUF_SIMPLE 0 -#define PyBUF_WRITABLE 0x0001 -/* we used to include an E, backwards compatible alias */ -#define PyBUF_WRITEABLE PyBUF_WRITABLE -#define PyBUF_FORMAT 0x0004 -#define PyBUF_ND 0x0008 -#define PyBUF_STRIDES (0x0010 | PyBUF_ND) -#define PyBUF_C_CONTIGUOUS (0x0020 | PyBUF_STRIDES) -#define PyBUF_F_CONTIGUOUS (0x0040 | PyBUF_STRIDES) -#define PyBUF_ANY_CONTIGUOUS (0x0080 | PyBUF_STRIDES) -#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES) - -#define PyBUF_CONTIG (PyBUF_ND | PyBUF_WRITABLE) -#define PyBUF_CONTIG_RO (PyBUF_ND) - -#define PyBUF_STRIDED (PyBUF_STRIDES | PyBUF_WRITABLE) -#define PyBUF_STRIDED_RO (PyBUF_STRIDES) - -#define PyBUF_RECORDS (PyBUF_STRIDES | PyBUF_WRITABLE | PyBUF_FORMAT) -#define PyBUF_RECORDS_RO (PyBUF_STRIDES | PyBUF_FORMAT) - -#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT) -#define PyBUF_FULL_RO (PyBUF_INDIRECT | PyBUF_FORMAT) - - -#define PyBUF_READ 0x100 -#define PyBUF_WRITE 0x200 -/* End buffer interface */ - typedef struct { /* Number implementations must check *both* diff --git a/Include/typeslots.h b/Include/typeslots.h index 5800d0158bc924..506b05580de146 100644 --- a/Include/typeslots.h +++ b/Include/typeslots.h @@ -1,12 +1,6 @@ /* Do not renumber the file; these numbers are part of the stable ABI. */ -#if defined(Py_LIMITED_API) -/* Disabled, see #10181 */ -#undef Py_bf_getbuffer -#undef Py_bf_releasebuffer -#else #define Py_bf_getbuffer 1 #define Py_bf_releasebuffer 2 -#endif #define Py_mp_ass_subscript 3 #define Py_mp_length 4 #define Py_mp_subscript 5 diff --git a/Makefile.pre.in b/Makefile.pre.in index 9de51711ac4c53..81a89989a72306 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1125,6 +1125,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/abstract.h \ $(srcdir)/Include/bltinmodule.h \ $(srcdir)/Include/boolobject.h \ + $(srcdir)/Include/buffer.h \ $(srcdir)/Include/bytearrayobject.h \ $(srcdir)/Include/bytesobject.h \ $(srcdir)/Include/ceval.h \ From fdfbe484bb673a6ee9172a5382d4d4aee1c3c336 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 18 Oct 2021 16:40:50 +0200 Subject: [PATCH 3/6] Hide typo alias with limited API --- Include/buffer.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Include/buffer.h b/Include/buffer.h index ee42024f451b6b..4a1ccf8e315e66 100644 --- a/Include/buffer.h +++ b/Include/buffer.h @@ -86,8 +86,12 @@ PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view); /* Flags for getting buffers */ #define PyBUF_SIMPLE 0 #define PyBUF_WRITABLE 0x0001 + +#ifndef Py_LIMITED_API /* we used to include an E, backwards compatible alias */ #define PyBUF_WRITEABLE PyBUF_WRITABLE +#endif + #define PyBUF_FORMAT 0x0004 #define PyBUF_ND 0x0008 #define PyBUF_STRIDES (0x0010 | PyBUF_ND) From 4a476c7b209d85eda911e1e9ee5ce3ac93ce094d Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 18 Oct 2021 16:41:34 +0200 Subject: [PATCH 4/6] Add PyBuffer_New / Free functions --- Include/buffer.h | 7 +++++++ Objects/abstract.c | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Include/buffer.h b/Include/buffer.h index 4a1ccf8e315e66..d6dc712a7a7396 100644 --- a/Include/buffer.h +++ b/Include/buffer.h @@ -77,6 +77,13 @@ PyAPI_FUNC(int) PyBuffer_FillInfo(Py_buffer *view, PyObject *o, void *buf, Py_ssize_t len, int readonly, int flags); +/* Allocate a new buffer struct on the heap. */ +PyAPI_FUNC(Py_buffer *) PyBuffer_New(void); + +/* Release and free buffer struct which has been allocated + by PyBuffer_New(). */ +PyAPI_FUNC(void) PyBuffer_Free(Py_buffer *view); + /* Releases a Py_buffer obtained from getbuffer ParseTuple's "s*". */ PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view); diff --git a/Objects/abstract.c b/Objects/abstract.c index 6f7b94600e278a..88255952a20d97 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -763,6 +763,25 @@ PyBuffer_Release(Py_buffer *view) Py_DECREF(obj); } +Py_buffer* +PyBuffer_New(void) +{ + Py_buffer *view = PyMem_Calloc(1, sizeof(Py_buffer)); + if (view == NULL) { + PyErr_NoMemory(); + } + return view; +} + +void +PyBuffer_Free(Py_buffer *view) +{ + if (view != NULL) { + PyBuffer_Release(view); + PyMem_Free(view); + } +} + PyObject * PyObject_Format(PyObject *obj, PyObject *format_spec) { From e2b80933a721635c8713b6584ac6eb398d4ea8d1 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 18 Oct 2021 16:46:39 +0200 Subject: [PATCH 5/6] Update stable_abi.txt --- Doc/data/stable_abi.dat | 13 +++++++++++++ Misc/stable_abi.txt | 28 ++++++++++++++++++++++++++++ PC/python3dll.c | 13 +++++++++++++ 3 files changed, 54 insertions(+) diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index b41027dee87bc8..66e0f932752062 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -10,6 +10,16 @@ function,PyArg_ValidateKeywordArguments,3.2, var,PyBaseObject_Type,3.2, function,PyBool_FromLong,3.2, var,PyBool_Type,3.2, +function,PyBuffer_FillContiguousStrides,3.11, +function,PyBuffer_FillInfo,3.11, +function,PyBuffer_Free,3.11, +function,PyBuffer_FromContiguous,3.11, +function,PyBuffer_GetPointer,3.11, +function,PyBuffer_IsContiguous,3.11, +function,PyBuffer_New,3.11, +function,PyBuffer_Release,3.11, +function,PyBuffer_SizeFromFormat,3.11, +function,PyBuffer_ToContiguous,3.11, var,PyByteArrayIter_Type,3.2, function,PyByteArray_AsString,3.2, function,PyByteArray_Concat,3.2, @@ -475,8 +485,10 @@ function,PyObject_CallMethodObjArgs,3.2, function,PyObject_CallNoArgs,3.10, function,PyObject_CallObject,3.2, function,PyObject_Calloc,3.7, +function,PyObject_CheckBuffer,3.11, function,PyObject_CheckReadBuffer,3.2, function,PyObject_ClearWeakRefs,3.2, +function,PyObject_CopyData,3.11, function,PyObject_DelItem,3.2, function,PyObject_DelItemString,3.2, function,PyObject_Dir,3.2, @@ -494,6 +506,7 @@ function,PyObject_GenericSetDict,3.7, function,PyObject_GetAIter,3.10, function,PyObject_GetAttr,3.2, function,PyObject_GetAttrString,3.2, +function,PyObject_GetBuffer,3.11, function,PyObject_GetItem,3.2, function,PyObject_GetIter,3.2, function,PyObject_HasAttr,3.2, diff --git a/Misc/stable_abi.txt b/Misc/stable_abi.txt index 8e79f521306220..14bac294f84710 100644 --- a/Misc/stable_abi.txt +++ b/Misc/stable_abi.txt @@ -2150,5 +2150,33 @@ function PyType_GetName function PyType_GetQualName added 3.11 +# Add stable Py_buffer API in Python 3.11 (https://bugs.python.org/issue45459) +function PyObject_CheckBuffer + added 3.11 +function PyObject_GetBuffer + added 3.11 +function PyBuffer_GetPointer + added 3.11 +function PyBuffer_SizeFromFormat + added 3.11 +function PyBuffer_ToContiguous + added 3.11 +function PyBuffer_FromContiguous + added 3.11 +function PyObject_CopyData + added 3.11 +function PyBuffer_IsContiguous + added 3.11 +function PyBuffer_FillContiguousStrides + added 3.11 +function PyBuffer_FillInfo + added 3.11 +function PyBuffer_New + added 3.11 +function PyBuffer_Free + added 3.11 +function PyBuffer_Release + added 3.11 + # (Detailed comments aren't really needed for further entries: from here on # we can use version control logs.) diff --git a/PC/python3dll.c b/PC/python3dll.c index 49b51e69d626e1..4f05f97efe5790 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -95,6 +95,16 @@ EXPORT_FUNC(PyArg_ValidateKeywordArguments) EXPORT_FUNC(PyArg_VaParse) EXPORT_FUNC(PyArg_VaParseTupleAndKeywords) EXPORT_FUNC(PyBool_FromLong) +EXPORT_FUNC(PyBuffer_FillContiguousStrides) +EXPORT_FUNC(PyBuffer_FillInfo) +EXPORT_FUNC(PyBuffer_Free) +EXPORT_FUNC(PyBuffer_FromContiguous) +EXPORT_FUNC(PyBuffer_GetPointer) +EXPORT_FUNC(PyBuffer_IsContiguous) +EXPORT_FUNC(PyBuffer_New) +EXPORT_FUNC(PyBuffer_Release) +EXPORT_FUNC(PyBuffer_SizeFromFormat) +EXPORT_FUNC(PyBuffer_ToContiguous) EXPORT_FUNC(PyByteArray_AsString) EXPORT_FUNC(PyByteArray_Concat) EXPORT_FUNC(PyByteArray_FromObject) @@ -427,8 +437,10 @@ EXPORT_FUNC(PyObject_CallMethodObjArgs) EXPORT_FUNC(PyObject_CallNoArgs) EXPORT_FUNC(PyObject_CallObject) EXPORT_FUNC(PyObject_Calloc) +EXPORT_FUNC(PyObject_CheckBuffer) EXPORT_FUNC(PyObject_CheckReadBuffer) EXPORT_FUNC(PyObject_ClearWeakRefs) +EXPORT_FUNC(PyObject_CopyData) EXPORT_FUNC(PyObject_DelItem) EXPORT_FUNC(PyObject_DelItemString) EXPORT_FUNC(PyObject_Dir) @@ -446,6 +458,7 @@ EXPORT_FUNC(PyObject_GenericSetDict) EXPORT_FUNC(PyObject_GetAIter) EXPORT_FUNC(PyObject_GetAttr) EXPORT_FUNC(PyObject_GetAttrString) +EXPORT_FUNC(PyObject_GetBuffer) EXPORT_FUNC(PyObject_GetItem) EXPORT_FUNC(PyObject_GetIter) EXPORT_FUNC(PyObject_HasAttr) From 718e69a6c9abfaaa3e475ad33d1abca4141966ce Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 18 Oct 2021 17:42:44 +0200 Subject: [PATCH 6/6] Add getters and setters --- Doc/data/stable_abi.dat | 7 ++++ Include/buffer.h | 16 +++++++ Misc/stable_abi.txt | 14 +++++++ Objects/abstract.c | 92 +++++++++++++++++++++++++++++++++++------ PC/python3dll.c | 7 ++++ 5 files changed, 123 insertions(+), 13 deletions(-) diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 66e0f932752062..238b31cae4d088 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -12,10 +12,17 @@ function,PyBool_FromLong,3.2, var,PyBool_Type,3.2, function,PyBuffer_FillContiguousStrides,3.11, function,PyBuffer_FillInfo,3.11, +function,PyBuffer_FillInfoEx,3.11, function,PyBuffer_Free,3.11, function,PyBuffer_FromContiguous,3.11, +function,PyBuffer_GetInternal,3.11, +function,PyBuffer_GetItemSize,3.11, +function,PyBuffer_GetLayout,3.11, +function,PyBuffer_GetLength,3.11, +function,PyBuffer_GetObject,3.11, function,PyBuffer_GetPointer,3.11, function,PyBuffer_IsContiguous,3.11, +function,PyBuffer_IsReadonly,3.11, function,PyBuffer_New,3.11, function,PyBuffer_Release,3.11, function,PyBuffer_SizeFromFormat,3.11, diff --git a/Include/buffer.h b/Include/buffer.h index d6dc712a7a7396..69a86c1c9c13c3 100644 --- a/Include/buffer.h +++ b/Include/buffer.h @@ -77,6 +77,13 @@ PyAPI_FUNC(int) PyBuffer_FillInfo(Py_buffer *view, PyObject *o, void *buf, Py_ssize_t len, int readonly, int flags); +PyAPI_FUNC(int) PyBuffer_FillInfoEx(Py_buffer *view, PyObject *obj, void *buf, + Py_ssize_t len, int readonly, int flags, + Py_ssize_t itemsize, int ndim, + char *format, Py_ssize_t *shape, + Py_ssize_t *strides, Py_ssize_t *suboffsets, + void *internal); + /* Allocate a new buffer struct on the heap. */ PyAPI_FUNC(Py_buffer *) PyBuffer_New(void); @@ -87,6 +94,15 @@ PyAPI_FUNC(void) PyBuffer_Free(Py_buffer *view); /* Releases a Py_buffer obtained from getbuffer ParseTuple's "s*". */ PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view); +PyAPI_FUNC(PyObject *) PyBuffer_GetObject(Py_buffer *view); +PyAPI_FUNC(Py_ssize_t) PyBuffer_GetLength(Py_buffer *view); +PyAPI_FUNC(Py_ssize_t) PyBuffer_GetItemSize(Py_buffer *view); +PyAPI_FUNC(int) PyBuffer_IsReadonly(Py_buffer *view); +PyAPI_FUNC(void *) PyBuffer_GetInternal(Py_buffer *view); +PyAPI_FUNC(int) PyBuffer_GetLayout(Py_buffer *view, char **format, + Py_ssize_t **shape, Py_ssize_t **strides, + Py_ssize_t **suboffsets); + /* Maximum number of dimensions */ #define PyBUF_MAX_NDIM 64 diff --git a/Misc/stable_abi.txt b/Misc/stable_abi.txt index 14bac294f84710..e99d7bf2ff0913 100644 --- a/Misc/stable_abi.txt +++ b/Misc/stable_abi.txt @@ -2171,12 +2171,26 @@ function PyBuffer_FillContiguousStrides added 3.11 function PyBuffer_FillInfo added 3.11 +function PyBuffer_FillInfoEx + added 3.11 function PyBuffer_New added 3.11 function PyBuffer_Free added 3.11 function PyBuffer_Release added 3.11 +function PyBuffer_GetObject + added 3.11 +function PyBuffer_GetLength + added 3.11 +function PyBuffer_GetItemSize + added 3.11 +function PyBuffer_IsReadonly + added 3.11 +function PyBuffer_GetInternal + added 3.11 +function PyBuffer_GetLayout + added 3.11 # (Detailed comments aren't really needed for further entries: from here on # we can use version control logs.) diff --git a/Objects/abstract.c b/Objects/abstract.c index 88255952a20d97..7310056e015fd5 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -709,10 +709,12 @@ PyBuffer_FillContiguousStrides(int nd, Py_ssize_t *shape, return; } + int -PyBuffer_FillInfo(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, - int readonly, int flags) -{ +PyBuffer_FillInfoEx(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, + int readonly, int flags, Py_ssize_t itemsize, int ndim, + char *format, Py_ssize_t *shape, Py_ssize_t *strides, + Py_ssize_t *suboffsets, void *internal) { if (view == NULL) { PyErr_SetString(PyExc_BufferError, "PyBuffer_FillInfo: view==NULL argument is obsolete"); @@ -726,28 +728,48 @@ PyBuffer_FillInfo(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, return -1; } + /* TODO: perform basic validation of arguments */ + view->obj = obj; if (obj) Py_INCREF(obj); view->buf = buf; view->len = len; view->readonly = readonly; - view->itemsize = 1; - view->format = NULL; - if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) + view->itemsize = itemsize; + + if ((format == NULL) && ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)) view->format = "B"; - view->ndim = 1; - view->shape = NULL; - if ((flags & PyBUF_ND) == PyBUF_ND) + else + view->format = format; + + view->ndim = ndim; + + if ((shape == NULL) && ((flags & PyBUF_ND) == PyBUF_ND)) view->shape = &(view->len); - view->strides = NULL; - if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) + else + view->shape = shape; + + if ((strides == NULL) && ((flags & PyBUF_STRIDES) == PyBUF_STRIDES)) view->strides = &(view->itemsize); - view->suboffsets = NULL; - view->internal = NULL; + else + view->strides = strides; + + view->suboffsets = suboffsets; + view->internal = internal; + return 0; } +int +PyBuffer_FillInfo(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, + int readonly, int flags) +{ + return PyBuffer_FillInfoEx( + view, obj, buf, len, readonly, flags, 1, 1, NULL, NULL, NULL, NULL, NULL + ); +} + void PyBuffer_Release(Py_buffer *view) { @@ -782,6 +804,50 @@ PyBuffer_Free(Py_buffer *view) } } +PyObject * +PyBuffer_GetObject(Py_buffer *view) { + return Py_XNewRef(view->obj); +} + +Py_ssize_t +PyBuffer_GetLength(Py_buffer *view) { + return view->len; +} + +Py_ssize_t +PyBuffer_GetItemSize(Py_buffer *view) { + return view->itemsize; +} + +int +PyBuffer_IsReadonly(Py_buffer *view) { + return view->readonly; +} + +void * +PyBuffer_GetInternal(Py_buffer *view) { + return view->internal; +} + +int +PyBuffer_GetLayout(Py_buffer *view, char **format, Py_ssize_t **shape, + Py_ssize_t **strides, Py_ssize_t **suboffsets) { + if (format != NULL) { + *format = view->format; + } + if (shape != NULL) { + *shape = view->shape; + } + if (strides != NULL) { + *strides = view->strides; + } + if (suboffsets != NULL) { + *suboffsets = view->suboffsets; + } + return view->ndim; +} + + PyObject * PyObject_Format(PyObject *obj, PyObject *format_spec) { diff --git a/PC/python3dll.c b/PC/python3dll.c index 4f05f97efe5790..a95109a36e4332 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -97,10 +97,17 @@ EXPORT_FUNC(PyArg_VaParseTupleAndKeywords) EXPORT_FUNC(PyBool_FromLong) EXPORT_FUNC(PyBuffer_FillContiguousStrides) EXPORT_FUNC(PyBuffer_FillInfo) +EXPORT_FUNC(PyBuffer_FillInfoEx) EXPORT_FUNC(PyBuffer_Free) EXPORT_FUNC(PyBuffer_FromContiguous) +EXPORT_FUNC(PyBuffer_GetInternal) +EXPORT_FUNC(PyBuffer_GetItemSize) +EXPORT_FUNC(PyBuffer_GetLayout) +EXPORT_FUNC(PyBuffer_GetLength) +EXPORT_FUNC(PyBuffer_GetObject) EXPORT_FUNC(PyBuffer_GetPointer) EXPORT_FUNC(PyBuffer_IsContiguous) +EXPORT_FUNC(PyBuffer_IsReadonly) EXPORT_FUNC(PyBuffer_New) EXPORT_FUNC(PyBuffer_Release) EXPORT_FUNC(PyBuffer_SizeFromFormat)