Skip to content

Commit 1edb036

Browse files
committed
CPython 3.13: add _PyLong_New() and import some macros from pycore_hash.h
Turn on basic tests on 3.13 Closes #417
1 parent e094479 commit 1edb036

File tree

3 files changed

+44
-1
lines changed

3 files changed

+44
-1
lines changed

.github/workflows/pip_install_gmpy2.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
strategy:
88
fail-fast: false
99
matrix:
10-
python-version: [3.11, 3.12]
10+
python-version: [3.11, 3.12, 3.13]
1111
os: [macos-latest]
1212
runs-on: ${{ matrix.os }}
1313
steps:

src/gmpy2_convert.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,44 @@ extern "C" {
154154
# define _PyLong_DigitCount(obj) (_PyLong_IsNegative(obj)? -Py_SIZE(obj):Py_SIZE(obj))
155155
#endif
156156

157+
#if PY_VERSION_HEX >= 0x030D0000
158+
159+
#define MAX_LONG_DIGITS \
160+
((PY_SSIZE_T_MAX - offsetof(PyLongObject, long_value.ob_digit))/sizeof(digit))
161+
162+
PyLongObject *
163+
_PyLong_New(Py_ssize_t size)
164+
{
165+
assert(size >= 0);
166+
PyLongObject *result;
167+
if (size > (Py_ssize_t)MAX_LONG_DIGITS) {
168+
PyErr_SetString(PyExc_OverflowError,
169+
"too many digits in integer");
170+
return NULL;
171+
}
172+
/* Fast operations for single digit integers (including zero)
173+
* assume that there is always at least one digit present. */
174+
Py_ssize_t ndigits = size ? size : 1;
175+
/* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +
176+
sizeof(digit)*size. Previous incarnations of this code used
177+
sizeof() instead of the offsetof, but this risks being
178+
incorrect in the presence of padding between the header
179+
and the digits. */
180+
result = PyObject_Malloc(offsetof(PyLongObject, long_value.ob_digit) +
181+
ndigits*sizeof(digit));
182+
if (!result) {
183+
PyErr_NoMemory();
184+
return NULL;
185+
}
186+
_PyLong_SetSignAndDigitCount(result, size != 0, size);
187+
PyObject_Init((PyObject*)result, &PyLong_Type);
188+
/* The digit has to be initialized explicitly to avoid
189+
* use-of-uninitialized-value. */
190+
result->long_value.ob_digit[0] = 0;
191+
return result;
192+
}
193+
#endif
194+
157195
/* Since the macros are used in gmpy2's codebase, these functions are skipped
158196
* until they are needed for the C API in the future.
159197
*/

src/gmpy2_hash.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
* License along with GMPY2; if not, see <http://www.gnu.org/licenses/> *
2525
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2626

27+
#if PY_VERSION_HEX >= 0x030D0000
28+
# define Py_BUILD_CORE
29+
# include <internal/pycore_pyhash.h>
30+
#endif
31+
2732
static Py_hash_t
2833
GMPy_MPZ_Hash_Slot(MPZ_Object *self)
2934
{

0 commit comments

Comments
 (0)