From bc84be3238a7b3d9c2677a1af2ae39f1d53854b1 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 27 Apr 2022 16:51:00 +0200 Subject: [PATCH] gh-89653: PEP 670: Convert PyBytes macros to functions Convert the following macros to static inline functions: * PyByteArray_AS_STRING() * PyByteArray_GET_SIZE() * PyBytes_AS_STRING() * PyBytes_GET_SIZE() Limited C API version 3.11 no longer casts arguments. Add _PyBytes_CAST() and _PyByteArray_CAST() macros. --- Doc/c-api/bytearray.rst | 4 ++-- Doc/c-api/bytes.rst | 4 ++-- Include/cpython/bytearrayobject.h | 30 ++++++++++++++++++++++++------ Include/cpython/bytesobject.h | 23 +++++++++++++++++++---- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/Doc/c-api/bytearray.rst b/Doc/c-api/bytearray.rst index 85a7d1373c2a81..4bf3cfe100cd01 100644 --- a/Doc/c-api/bytearray.rst +++ b/Doc/c-api/bytearray.rst @@ -77,9 +77,9 @@ These macros trade safety for speed and they don't check pointers. .. c:function:: char* PyByteArray_AS_STRING(PyObject *bytearray) - Macro version of :c:func:`PyByteArray_AsString`. + Similar to :c:func:`PyByteArray_AsString`, but without error checking. .. c:function:: Py_ssize_t PyByteArray_GET_SIZE(PyObject *bytearray) - Macro version of :c:func:`PyByteArray_Size`. + Similar to :c:func:`PyByteArray_Size`, but without error checking. diff --git a/Doc/c-api/bytes.rst b/Doc/c-api/bytes.rst index 32c7b80dc7ac63..d47f0422e61004 100644 --- a/Doc/c-api/bytes.rst +++ b/Doc/c-api/bytes.rst @@ -134,7 +134,7 @@ called with a non-bytes parameter. .. c:function:: Py_ssize_t PyBytes_GET_SIZE(PyObject *o) - Macro form of :c:func:`PyBytes_Size` but without error checking. + Similar to :c:func:`PyBytes_Size`, but without error checking. .. c:function:: char* PyBytes_AsString(PyObject *o) @@ -151,7 +151,7 @@ called with a non-bytes parameter. .. c:function:: char* PyBytes_AS_STRING(PyObject *string) - Macro form of :c:func:`PyBytes_AsString` but without error checking. + Similar to :c:func:`PyBytes_AsString`, but without error checking. .. c:function:: int PyBytes_AsStringAndSize(PyObject *obj, char **buffer, Py_ssize_t *length) diff --git a/Include/cpython/bytearrayobject.h b/Include/cpython/bytearrayobject.h index 569b0cd0369861..5114169c280915 100644 --- a/Include/cpython/bytearrayobject.h +++ b/Include/cpython/bytearrayobject.h @@ -11,10 +11,28 @@ typedef struct { Py_ssize_t ob_exports; /* How many buffer exports */ } PyByteArrayObject; -/* Macros, trading safety for speed */ -#define PyByteArray_AS_STRING(self) \ - (assert(PyByteArray_Check(self)), \ - Py_SIZE(self) ? ((PyByteArrayObject *)(self))->ob_start : _PyByteArray_empty_string) -#define PyByteArray_GET_SIZE(self) (assert(PyByteArray_Check(self)), Py_SIZE(self)) - PyAPI_DATA(char) _PyByteArray_empty_string[]; + +/* Macros and static inline functions, trading safety for speed */ +#define _PyByteArray_CAST(op) \ + (assert(PyByteArray_Check(op)), _Py_CAST(PyByteArrayObject*, op)) + +static inline char* PyByteArray_AS_STRING(PyObject *op) +{ + PyByteArrayObject *self = _PyByteArray_CAST(op); + if (Py_SIZE(self)) { + return self->ob_start; + } + return _PyByteArray_empty_string; +} +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 +# define PyByteArray_AS_STRING(self) PyByteArray_AS_STRING(_PyObject_CAST(self)) +#endif + +static inline Py_ssize_t PyByteArray_GET_SIZE(PyObject *op) { + PyByteArrayObject *self = _PyByteArray_CAST(op); + return Py_SIZE(self); +} +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 +# define PyByteArray_GET_SIZE(self) PyByteArray_GET_SIZE(_PyObject_CAST(self)) +#endif diff --git a/Include/cpython/bytesobject.h b/Include/cpython/bytesobject.h index 2c6d631f0b21e0..53343661f0ec43 100644 --- a/Include/cpython/bytesobject.h +++ b/Include/cpython/bytesobject.h @@ -28,10 +28,25 @@ PyAPI_FUNC(PyObject*) _PyBytes_FromHex( PyAPI_FUNC(PyObject *) _PyBytes_DecodeEscape(const char *, Py_ssize_t, const char *, const char **); -/* Macro, trading safety for speed */ -#define PyBytes_AS_STRING(op) (assert(PyBytes_Check(op)), \ - (((PyBytesObject *)(op))->ob_sval)) -#define PyBytes_GET_SIZE(op) (assert(PyBytes_Check(op)),Py_SIZE(op)) +/* Macros and static inline functions, trading safety for speed */ +#define _PyBytes_CAST(op) \ + (assert(PyBytes_Check(op)), _Py_CAST(PyBytesObject*, op)) + +static inline char* PyBytes_AS_STRING(PyObject *op) +{ + return _PyBytes_CAST(op)->ob_sval; +} +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 +# define PyBytes_AS_STRING(op) PyBytes_AS_STRING(_PyObject_CAST(op)) +#endif + +static inline Py_ssize_t PyBytes_GET_SIZE(PyObject *op) { + PyBytesObject *self = _PyBytes_CAST(op); + return Py_SIZE(self); +} +#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 +# define PyBytes_GET_SIZE(self) PyBytes_GET_SIZE(_PyObject_CAST(self)) +#endif /* _PyBytes_Join(sep, x) is like sep.join(x). sep must be PyBytesObject*, x must be an iterable object. */