Skip to content

Commit

Permalink
gh-106320: Remove private _PyLong_IsCompact() function
Browse files Browse the repository at this point in the history
Move the private _PyLong_IsCompact() and _PyLong_CompactValue()
functions to the internal C API (pycore_long.h). Public
PyUnstable_Long_IsCompact() and PyUnstable_Long_CompactValue()
functions can be used instead.

Remove "const" qualifier from PyUnstable_Long_IsCompact() and
PyUnstable_Long_CompactValue() parameter type.
  • Loading branch information
vstinner committed Sep 1, 2023
1 parent 3edcf74 commit c6be6f8
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 51 deletions.
4 changes: 2 additions & 2 deletions Doc/c-api/long.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down
28 changes: 0 additions & 28 deletions Include/cpython/longintrepr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 2 additions & 3 deletions Include/cpython/longobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
34 changes: 21 additions & 13 deletions Include/internal/pycore_long.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,37 +231,45 @@ 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.
* In other words, for 64 bit machines, compact
* 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) {
Expand Down
7 changes: 2 additions & 5 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit c6be6f8

Please sign in to comment.