Skip to content

Commit b178c0a

Browse files
authored
Merge pull request #138 from tornaria/py312
Support python 3.12
2 parents 57ab63c + 932da8b commit b178c0a

File tree

6 files changed

+121
-30
lines changed

6 files changed

+121
-30
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
fail-fast: false
2020
matrix:
2121
os: [ubuntu-latest]
22-
python-version: ['3.10', '3.11']
22+
python-version: ['3.9', '3.10', '3.11', '3.12']
2323
pari-version: ['pari-2.11.4', 'pari-2.13.0', 'pari-2.15.4']
2424
env:
2525
LC_ALL: C

autogen/paths.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515
from __future__ import absolute_import, unicode_literals
1616

1717
import os
18+
import shutil
19+
1820
from glob import glob
19-
from distutils.spawn import find_executable
2021

2122

22-
# find_executable() returns None if nothing was found
23-
gppath = find_executable("gp")
23+
gppath = shutil.which("gp")
24+
2425
if gppath is None:
2526
# This almost certainly won't work, but we need to put something here
2627
prefix = "."

cypari2/Py_SET_SIZE.h

Lines changed: 0 additions & 8 deletions
This file was deleted.

cypari2/convert.pyx

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,8 @@ from libc.math cimport INFINITY
5454
from .paridecl cimport *
5555
from .stack cimport new_gen, reset_avma
5656
from .string_utils cimport to_string, to_bytes
57-
58-
cdef extern from *:
59-
ctypedef struct PyLongObject:
60-
digit* ob_digit
61-
62-
cdef extern from "Py_SET_SIZE.h":
63-
void Py_SET_SIZE(py_long o, Py_ssize_t size)
64-
57+
from .pycore_long cimport (ob_digit, _PyLong_IsZero, _PyLong_IsNegative,
58+
_PyLong_IsPositive, _PyLong_DigitCount, _PyLong_SetSignAndDigitCount)
6559

6660
########################################################################
6761
# Conversion PARI -> Python
@@ -424,7 +418,7 @@ cdef PyLong_FromINT(GEN g):
424418
cdef Py_ssize_t sizedigits_final = 0
425419

426420
cdef py_long x = _PyLong_New(sizedigits)
427-
cdef digit* D = x.ob_digit
421+
cdef digit* D = ob_digit(x)
428422

429423
cdef digit d
430424
cdef ulong w
@@ -452,10 +446,7 @@ cdef PyLong_FromINT(GEN g):
452446
sizedigits_final = i+1
453447

454448
# Set correct size
455-
if signe(g) > 0:
456-
Py_SET_SIZE(x, sizedigits_final)
457-
else:
458-
Py_SET_SIZE(x, -sizedigits_final)
449+
_PyLong_SetSignAndDigitCount(x, signe(g), sizedigits_final)
459450

460451
return x
461452

@@ -465,18 +456,18 @@ cdef PyLong_FromINT(GEN g):
465456
########################################################################
466457

467458
cdef GEN PyLong_AS_GEN(py_long x):
468-
cdef const digit* D = x.ob_digit
459+
cdef const digit* D = ob_digit(x)
469460

470461
# Size of the input
471462
cdef size_t sizedigits
472463
cdef long sgn
473-
if Py_SIZE(x) == 0:
464+
if _PyLong_IsZero(x):
474465
return gen_0
475-
elif Py_SIZE(x) > 0:
476-
sizedigits = Py_SIZE(x)
466+
elif _PyLong_IsPositive(x):
467+
sizedigits = _PyLong_DigitCount(x)
477468
sgn = evalsigne(1)
478469
else:
479-
sizedigits = -Py_SIZE(x)
470+
sizedigits = _PyLong_DigitCount(x)
480471
sgn = evalsigne(-1)
481472

482473
# Size of the output, in bits and in words

cypari2/pycore_long.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#include "Python.h"
2+
#include <stdbool.h>
3+
4+
#if PY_VERSION_HEX >= 0x030C00A5
5+
#define ob_digit(o) (((PyLongObject*)o)->long_value.ob_digit)
6+
#else
7+
#define ob_digit(o) (((PyLongObject*)o)->ob_digit)
8+
#endif
9+
10+
#if PY_VERSION_HEX >= 0x030C00A7
11+
// taken from cpython:Include/internal/pycore_long.h @ 3.12
12+
13+
/* Long value tag bits:
14+
* 0-1: Sign bits value = (1-sign), ie. negative=2, positive=0, zero=1.
15+
* 2: Reserved for immortality bit
16+
* 3+ Unsigned digit count
17+
*/
18+
#define SIGN_MASK 3
19+
#define SIGN_ZERO 1
20+
#define SIGN_NEGATIVE 2
21+
#define NON_SIZE_BITS 3
22+
23+
static inline bool
24+
_PyLong_IsZero(const PyLongObject *op)
25+
{
26+
return (op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO;
27+
}
28+
29+
static inline bool
30+
_PyLong_IsNegative(const PyLongObject *op)
31+
{
32+
return (op->long_value.lv_tag & SIGN_MASK) == SIGN_NEGATIVE;
33+
}
34+
35+
static inline bool
36+
_PyLong_IsPositive(const PyLongObject *op)
37+
{
38+
return (op->long_value.lv_tag & SIGN_MASK) == 0;
39+
}
40+
41+
static inline Py_ssize_t
42+
_PyLong_DigitCount(const PyLongObject *op)
43+
{
44+
assert(PyLong_Check(op));
45+
return op->long_value.lv_tag >> NON_SIZE_BITS;
46+
}
47+
48+
#define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS))
49+
50+
static inline void
51+
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
52+
{
53+
assert(size >= 0);
54+
assert(-1 <= sign && sign <= 1);
55+
assert(sign != 0 || size == 0);
56+
op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, (size_t)size);
57+
}
58+
59+
#else
60+
// fallback for < 3.12
61+
62+
static inline bool
63+
_PyLong_IsZero(const PyLongObject *op)
64+
{
65+
return Py_SIZE(op) == 0;
66+
}
67+
68+
static inline bool
69+
_PyLong_IsNegative(const PyLongObject *op)
70+
{
71+
return Py_SIZE(op) < 0;
72+
}
73+
74+
static inline bool
75+
_PyLong_IsPositive(const PyLongObject *op)
76+
{
77+
return Py_SIZE(op) > 0;
78+
}
79+
80+
static inline Py_ssize_t
81+
_PyLong_DigitCount(const PyLongObject *op)
82+
{
83+
Py_ssize_t size = Py_SIZE(op);
84+
return size < 0 ? -size : size;
85+
}
86+
87+
static inline void
88+
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
89+
{
90+
#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION < 9)
91+
// The function Py_SET_SIZE is defined starting with python 3.9.
92+
Py_SIZE(o) = size;
93+
#else
94+
Py_SET_SIZE(op, sign < 0 ? -size : size);
95+
#endif
96+
}
97+
98+
#endif

cypari2/pycore_long.pxd

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from cpython.longintrepr cimport py_long, digit
2+
3+
cdef extern from "pycore_long.h":
4+
digit* ob_digit(py_long o)
5+
bint _PyLong_IsZero(py_long o)
6+
bint _PyLong_IsNegative(py_long o)
7+
bint _PyLong_IsPositive(py_long o)
8+
Py_ssize_t _PyLong_DigitCount(py_long o)
9+
void _PyLong_SetSignAndDigitCount(py_long o, int sign, Py_ssize_t size)

0 commit comments

Comments
 (0)