Skip to content

Commit

Permalink
Merge pull request #138 from tornaria/py312
Browse files Browse the repository at this point in the history
Support python 3.12
  • Loading branch information
dimpase authored Oct 10, 2023
2 parents 57ab63c + 932da8b commit b178c0a
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 30 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: ['3.10', '3.11']
python-version: ['3.9', '3.10', '3.11', '3.12']
pari-version: ['pari-2.11.4', 'pari-2.13.0', 'pari-2.15.4']
env:
LC_ALL: C
Expand Down
7 changes: 4 additions & 3 deletions autogen/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
from __future__ import absolute_import, unicode_literals

import os
import shutil

from glob import glob
from distutils.spawn import find_executable


# find_executable() returns None if nothing was found
gppath = find_executable("gp")
gppath = shutil.which("gp")

if gppath is None:
# This almost certainly won't work, but we need to put something here
prefix = "."
Expand Down
8 changes: 0 additions & 8 deletions cypari2/Py_SET_SIZE.h

This file was deleted.

27 changes: 9 additions & 18 deletions cypari2/convert.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,8 @@ from libc.math cimport INFINITY
from .paridecl cimport *
from .stack cimport new_gen, reset_avma
from .string_utils cimport to_string, to_bytes

cdef extern from *:
ctypedef struct PyLongObject:
digit* ob_digit

cdef extern from "Py_SET_SIZE.h":
void Py_SET_SIZE(py_long o, Py_ssize_t size)

from .pycore_long cimport (ob_digit, _PyLong_IsZero, _PyLong_IsNegative,
_PyLong_IsPositive, _PyLong_DigitCount, _PyLong_SetSignAndDigitCount)

########################################################################
# Conversion PARI -> Python
Expand Down Expand Up @@ -424,7 +418,7 @@ cdef PyLong_FromINT(GEN g):
cdef Py_ssize_t sizedigits_final = 0

cdef py_long x = _PyLong_New(sizedigits)
cdef digit* D = x.ob_digit
cdef digit* D = ob_digit(x)

cdef digit d
cdef ulong w
Expand Down Expand Up @@ -452,10 +446,7 @@ cdef PyLong_FromINT(GEN g):
sizedigits_final = i+1

# Set correct size
if signe(g) > 0:
Py_SET_SIZE(x, sizedigits_final)
else:
Py_SET_SIZE(x, -sizedigits_final)
_PyLong_SetSignAndDigitCount(x, signe(g), sizedigits_final)

return x

Expand All @@ -465,18 +456,18 @@ cdef PyLong_FromINT(GEN g):
########################################################################

cdef GEN PyLong_AS_GEN(py_long x):
cdef const digit* D = x.ob_digit
cdef const digit* D = ob_digit(x)

# Size of the input
cdef size_t sizedigits
cdef long sgn
if Py_SIZE(x) == 0:
if _PyLong_IsZero(x):
return gen_0
elif Py_SIZE(x) > 0:
sizedigits = Py_SIZE(x)
elif _PyLong_IsPositive(x):
sizedigits = _PyLong_DigitCount(x)
sgn = evalsigne(1)
else:
sizedigits = -Py_SIZE(x)
sizedigits = _PyLong_DigitCount(x)
sgn = evalsigne(-1)

# Size of the output, in bits and in words
Expand Down
98 changes: 98 additions & 0 deletions cypari2/pycore_long.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include "Python.h"
#include <stdbool.h>

#if PY_VERSION_HEX >= 0x030C00A5
#define ob_digit(o) (((PyLongObject*)o)->long_value.ob_digit)
#else
#define ob_digit(o) (((PyLongObject*)o)->ob_digit)
#endif

#if PY_VERSION_HEX >= 0x030C00A7
// taken from cpython:Include/internal/pycore_long.h @ 3.12

/* 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_ZERO 1
#define SIGN_NEGATIVE 2
#define NON_SIZE_BITS 3

static inline bool
_PyLong_IsZero(const PyLongObject *op)
{
return (op->long_value.lv_tag & SIGN_MASK) == SIGN_ZERO;
}

static inline bool
_PyLong_IsNegative(const PyLongObject *op)
{
return (op->long_value.lv_tag & SIGN_MASK) == SIGN_NEGATIVE;
}

static inline bool
_PyLong_IsPositive(const PyLongObject *op)
{
return (op->long_value.lv_tag & SIGN_MASK) == 0;
}

static inline Py_ssize_t
_PyLong_DigitCount(const PyLongObject *op)
{
assert(PyLong_Check(op));
return op->long_value.lv_tag >> NON_SIZE_BITS;
}

#define TAG_FROM_SIGN_AND_SIZE(sign, size) ((1 - (sign)) | ((size) << NON_SIZE_BITS))

static inline void
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
{
assert(size >= 0);
assert(-1 <= sign && sign <= 1);
assert(sign != 0 || size == 0);
op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, (size_t)size);
}

#else
// fallback for < 3.12

static inline bool
_PyLong_IsZero(const PyLongObject *op)
{
return Py_SIZE(op) == 0;
}

static inline bool
_PyLong_IsNegative(const PyLongObject *op)
{
return Py_SIZE(op) < 0;
}

static inline bool
_PyLong_IsPositive(const PyLongObject *op)
{
return Py_SIZE(op) > 0;
}

static inline Py_ssize_t
_PyLong_DigitCount(const PyLongObject *op)
{
Py_ssize_t size = Py_SIZE(op);
return size < 0 ? -size : size;
}

static inline void
_PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
{
#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION < 9)
// The function Py_SET_SIZE is defined starting with python 3.9.
Py_SIZE(o) = size;
#else
Py_SET_SIZE(op, sign < 0 ? -size : size);
#endif
}

#endif
9 changes: 9 additions & 0 deletions cypari2/pycore_long.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from cpython.longintrepr cimport py_long, digit

cdef extern from "pycore_long.h":
digit* ob_digit(py_long o)
bint _PyLong_IsZero(py_long o)
bint _PyLong_IsNegative(py_long o)
bint _PyLong_IsPositive(py_long o)
Py_ssize_t _PyLong_DigitCount(py_long o)
void _PyLong_SetSignAndDigitCount(py_long o, int sign, Py_ssize_t size)

0 comments on commit b178c0a

Please sign in to comment.