diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index 045604870d3c84..01528dac8a1e74 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -332,7 +332,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Returns ``NULL`` on error. Use :c:func:`PyErr_Occurred` to disambiguate. -.. c:function:: int PyUnstable_Long_IsCompact(const PyLongObject* op) +.. c:function:: int PyUnstable_Long_IsCompact(PyLongObject* op) Return 1 if *op* is compact, 0 otherwise. @@ -347,7 +347,7 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate. Exactly what values are considered compact is an implementation detail and is subject to change. -.. c:function:: Py_ssize_t PyUnstable_Long_CompactValue(const PyLongObject* op) +.. c:function:: Py_ssize_t PyUnstable_Long_CompactValue(PyLongObject* op) If *op* is compact, as determined by :c:func:`PyUnstable_Long_IsCompact`, return its value. diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index fb82f83dc50e42..794e22d60b55f8 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -89,34 +89,6 @@ struct _longobject { _PyLongValue long_value; }; - -/* Inline some internals for speed. These should be in pycore_long.h - * if user code didn't need them inlined. */ - -#define _PyLong_SIGN_MASK 3 -#define _PyLong_NON_SIZE_BITS 3 - - -static inline int -_PyLong_IsCompact(const PyLongObject* op) { - assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); - return op->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS); -} - -#define PyUnstable_Long_IsCompact _PyLong_IsCompact - -static inline Py_ssize_t -_PyLong_CompactValue(const PyLongObject *op) -{ - assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); - assert(PyUnstable_Long_IsCompact(op)); - Py_ssize_t sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); - return sign * (Py_ssize_t)op->long_value.ob_digit[0]; -} - -#define PyUnstable_Long_CompactValue _PyLong_CompactValue - - #ifdef __cplusplus } #endif diff --git a/Include/cpython/longobject.h b/Include/cpython/longobject.h index 57834173490c99..f62086c711ad93 100644 --- a/Include/cpython/longobject.h +++ b/Include/cpython/longobject.h @@ -4,6 +4,5 @@ PyAPI_FUNC(PyObject*) PyLong_FromUnicodeObject(PyObject *u, int base); -PyAPI_FUNC(int) PyUnstable_Long_IsCompact(const PyLongObject* op); -PyAPI_FUNC(Py_ssize_t) PyUnstable_Long_CompactValue(const PyLongObject* op); - +PyAPI_FUNC(int) PyUnstable_Long_IsCompact(PyLongObject* op); +PyAPI_FUNC(Py_ssize_t) PyUnstable_Long_CompactValue(PyLongObject* op); diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h index 3c253ed7ff556b..8574e6d23beebc 100644 --- a/Include/internal/pycore_long.h +++ b/Include/internal/pycore_long.h @@ -231,30 +231,23 @@ PyAPI_FUNC(int) _PyLong_UnsignedLongLong_Converter(PyObject *, void *); // Export for '_testclinic' shared extension (Argument Clinic code) PyAPI_FUNC(int) _PyLong_Size_t_Converter(PyObject *, void *); +#define _PyLong_SIGN_MASK 3 +#define _PyLong_NON_SIZE_BITS 3 + /* Long value tag bits: * 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1. * 2: Reserved for immortality bit * 3+ Unsigned digit count */ -#define SIGN_MASK 3 +#define SIGN_MASK _PyLong_SIGN_MASK #define SIGN_ZERO 1 #define SIGN_NEGATIVE 2 -#define NON_SIZE_BITS 3 +#define NON_SIZE_BITS _PyLong_NON_SIZE_BITS -/* The functions _PyLong_IsCompact and _PyLong_CompactValue are defined - * in Include/cpython/longobject.h, since they need to be inline. - * - * "Compact" values have at least one bit to spare, +/* "Compact" values have at least one bit to spare, * so that addition and subtraction can be performed on the values * without risk of overflow. - * - * The inline functions need tag bits. - * For readability, rather than do `#define SIGN_MASK _PyLong_SIGN_MASK` - * we define them to the numbers in both places and then assert that - * they're the same. */ -static_assert(SIGN_MASK == _PyLong_SIGN_MASK, "SIGN_MASK does not match _PyLong_SIGN_MASK"); -static_assert(NON_SIZE_BITS == _PyLong_NON_SIZE_BITS, "NON_SIZE_BITS does not match _PyLong_NON_SIZE_BITS"); /* All *compact" values are guaranteed to fit into * a Py_ssize_t with at least one bit to spare. @@ -262,6 +255,21 @@ static_assert(NON_SIZE_BITS == _PyLong_NON_SIZE_BITS, "NON_SIZE_BITS does not ma * will be signed 63 (or fewer) bit values */ +static inline int +_PyLong_IsCompact(const PyLongObject* op) { + assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); + return op->long_value.lv_tag < (2 << _PyLong_NON_SIZE_BITS); +} + +static inline Py_ssize_t +_PyLong_CompactValue(const PyLongObject *op) +{ + assert(PyType_HasFeature((op)->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS)); + assert(_PyLong_IsCompact(op)); + Py_ssize_t sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK); + return sign * (Py_ssize_t)op->long_value.ob_digit[0]; +} + /* Return 1 if the argument is compact int */ static inline int _PyLong_IsNonNegativeCompact(const PyLongObject* op) { diff --git a/Objects/longobject.c b/Objects/longobject.c index d20ef412367bb7..f8cb3e2183e76c 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -6369,16 +6369,13 @@ _PyLong_FiniTypes(PyInterpreterState *interp) _PyStructSequence_FiniBuiltin(interp, &Int_InfoType); } -#undef PyUnstable_Long_IsCompact int -PyUnstable_Long_IsCompact(const PyLongObject* op) { +PyUnstable_Long_IsCompact(PyLongObject* op) { return _PyLong_IsCompact(op); } -#undef PyUnstable_Long_CompactValue - Py_ssize_t -PyUnstable_Long_CompactValue(const PyLongObject* op) { +PyUnstable_Long_CompactValue(PyLongObject* op) { return _PyLong_CompactValue(op); }