blob: 1171322e26a88a96ce7d45fedc6d76db19609f68 [file] [log] [blame]
Patrick Williams705982a2024-01-12 09:51:57 -06001From 43f132103cedfd92b85173bcdacfbabd5916d9fc Mon Sep 17 00:00:00 2001
2From: Alexander Kanavin <alex@linutronix.de>
3Date: Wed, 27 Dec 2023 14:52:16 +0100
4Subject: [PATCH] src: fix python 3.12 builds
5
6This is a backport for 3.1.x versions provided separately in https://github.com/aleaxit/gmpy/issues/446
7
8Upstream-Status: Inappropriate [can be dropped when 2.2.x is released]
9
10Signed-off-by: Alexander Kanavin <alex@linutronix.de>
11---
12 src/gmpy2_convert.h | 21 +++++++
13 src/gmpy2_convert_gmp.c | 129 +++++++++++++-------------------------
14 src/gmpy2_convert_utils.c | 2 +-
15 3 files changed, 65 insertions(+), 87 deletions(-)
16
17diff --git a/src/gmpy2_convert.h b/src/gmpy2_convert.h
18index f887d47..3e8cb2b 100644
19--- a/src/gmpy2_convert.h
20+++ b/src/gmpy2_convert.h
21@@ -142,6 +142,27 @@ extern "C" {
22 #define IS_TYPE_COMPLEX_ONLY(x) ((x > OBJ_TYPE_REAL) && \
23 (x < OBJ_TYPE_COMPLEX))
24
25+/* Compatibility macros (to work with PyLongObject internals).
26+ */
27+
28+#if PY_VERSION_HEX >= 0x030C0000
29+# define TAG_FROM_SIGN_AND_SIZE(is_neg, size) ((is_neg?2:(size==0)) | (((size_t)size) << 3))
30+# define _PyLong_SetSignAndDigitCount(obj, is_neg, size) (obj->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(is_neg, size))
31+#elif PY_VERSION_HEX >= 0x030900A4
32+# define _PyLong_SetSignAndDigitCount(obj, is_neg, size) (Py_SET_SIZE(obj, (is_neg?-1:1)*size))
33+#else
34+# define _PyLong_SetSignAndDigitCount(obj, is_neg, size) (Py_SIZE(obj) = (is_neg?-1:1)*size)
35+#endif
36+
37+#if PY_VERSION_HEX >= 0x030C0000
38+# define GET_OB_DIGIT(obj) obj->long_value.ob_digit
39+# define _PyLong_IsNegative(obj) ((obj->long_value.lv_tag & 3) == 2)
40+# define _PyLong_DigitCount(obj) (obj->long_value.lv_tag >> 3)
41+#else
42+# define GET_OB_DIGIT(obj) obj->ob_digit
43+# define _PyLong_IsNegative(obj) (Py_SIZE(obj) < 0)
44+# define _PyLong_DigitCount(obj) (_PyLong_IsNegative(obj)? -Py_SIZE(obj):Py_SIZE(obj))
45+#endif
46
47 /* Since the macros are used in gmpy2's codebase, these functions are skipped
48 * until they are needed for the C API in the future.
49diff --git a/src/gmpy2_convert_gmp.c b/src/gmpy2_convert_gmp.c
50index cf0891e..8b8df81 100644
51--- a/src/gmpy2_convert_gmp.c
52+++ b/src/gmpy2_convert_gmp.c
53@@ -59,33 +59,24 @@ GMPy_MPZ_From_PyIntOrLong(PyObject *obj, CTXT_Object *context)
54 }
55 #endif
56
57- switch (Py_SIZE(templong)) {
58- case -1:
59- mpz_set_si(result->z, -(sdigit)templong->ob_digit[0]);
60+ len = _PyLong_DigitCount(templong);
61+ negative = _PyLong_IsNegative(templong);
62+
63+ switch (len) {
64+ case 1:
65+ mpz_set_si(result->z, (sdigit)GET_OB_DIGIT(templong)[0]);
66 break;
67 case 0:
68 mpz_set_si(result->z, 0);
69 break;
70- case 1:
71- mpz_set_si(result->z, templong->ob_digit[0]);
72- break;
73 default:
74- mpz_set_si(result->z, 0);
75-
76- if (Py_SIZE(templong) < 0) {
77- len = - Py_SIZE(templong);
78- negative = 1;
79- } else {
80- len = Py_SIZE(templong);
81- negative = 0;
82- }
83-
84- mpz_import(result->z, len, -1, sizeof(templong->ob_digit[0]), 0,
85- sizeof(templong->ob_digit[0])*8 - PyLong_SHIFT, templong->ob_digit);
86+ mpz_import(result->z, len, -1, sizeof(GET_OB_DIGIT(templong)[0]), 0,
87+ sizeof(GET_OB_DIGIT(templong)[0])*8 - PyLong_SHIFT,
88+ GET_OB_DIGIT(templong));
89+ }
90
91- if (negative) {
92- mpz_neg(result->z, result->z);
93- }
94+ if (negative) {
95+ mpz_neg(result->z, result->z);
96 }
97 return result;
98 }
99@@ -105,33 +96,24 @@ mpz_set_PyIntOrLong(mpz_t z, PyObject *obj)
100 }
101 #endif
102
103- switch (Py_SIZE(templong)) {
104- case -1:
105- mpz_set_si(z, -(sdigit)templong->ob_digit[0]);
106+ len = _PyLong_DigitCount(templong);
107+ negative = _PyLong_IsNegative(templong);
108+
109+ switch (len) {
110+ case 1:
111+ mpz_set_si(z, (sdigit)GET_OB_DIGIT(templong)[0]);
112 break;
113 case 0:
114 mpz_set_si(z, 0);
115 break;
116- case 1:
117- mpz_set_si(z, templong->ob_digit[0]);
118- break;
119 default:
120- mpz_set_si(z, 0);
121-
122- if (Py_SIZE(templong) < 0) {
123- len = - Py_SIZE(templong);
124- negative = 1;
125- } else {
126- len = Py_SIZE(templong);
127- negative = 0;
128- }
129-
130- mpz_import(z, len, -1, sizeof(templong->ob_digit[0]), 0,
131- sizeof(templong->ob_digit[0])*8 - PyLong_SHIFT, templong->ob_digit);
132+ mpz_import(z, len, -1, sizeof(GET_OB_DIGIT(templong)[0]), 0,
133+ sizeof(GET_OB_DIGIT(templong)[0])*8 - PyLong_SHIFT,
134+ GET_OB_DIGIT(templong));
135+ }
136
137- if (negative) {
138- mpz_neg(z, z);
139- }
140+ if (negative) {
141+ mpz_neg(z, z);
142 }
143 return;
144 }
145@@ -186,12 +168,7 @@ GMPy_PyLong_From_MPZ(MPZ_Object *obj, CTXT_Object *context)
146
147 /* Assume gmp uses limbs as least as large as the builtin longs do */
148
149- if (mpz_sgn(obj->z) < 0) {
150- negative = 1;
151- } else {
152- negative = 0;
153- }
154-
155+ negative = mpz_sgn(obj->z) < 0;
156 size = (mpz_sizeinbase(obj->z, 2) + PyLong_SHIFT - 1) / PyLong_SHIFT;
157
158 if (!(result = _PyLong_New(size))) {
159@@ -200,31 +177,20 @@ GMPy_PyLong_From_MPZ(MPZ_Object *obj, CTXT_Object *context)
160 /* LCOV_EXCL_STOP */
161 }
162
163- mpz_export(result->ob_digit, &count, -1, sizeof(result->ob_digit[0]), 0,
164- sizeof(result->ob_digit[0])*8 - PyLong_SHIFT, obj->z);
165+ mpz_export(GET_OB_DIGIT(result), &count, -1, sizeof(GET_OB_DIGIT(result)[0]), 0,
166+ sizeof(GET_OB_DIGIT(result)[0])*8 - PyLong_SHIFT, obj->z);
167
168 if (count == 0) {
169- result->ob_digit[0] = 0;
170+ GET_OB_DIGIT(result)[0] = 0;
171 }
172
173 /* long_normalize() is file-static so we must reimplement it */
174 /* longobjp = long_normalize(longobjp); */
175- while ((size>0) && (result->ob_digit[size-1] == 0)) {
176+ while ((size>0) && (GET_OB_DIGIT(result)[size-1] == 0)) {
177 size--;
178 }
179-#if PY_VERSION_HEX >= 0x030900A4
180- Py_SET_SIZE(result, size);
181-#else
182- Py_SIZE(result) = size;
183-#endif
184
185- if (negative) {
186-#if PY_VERSION_HEX >= 0x030900A4
187- Py_SET_SIZE(result, - Py_SIZE(result));
188-#else
189- Py_SIZE(result) = - Py_SIZE(result);
190-#endif
191- }
192+ _PyLong_SetSignAndDigitCount(result, negative, size);
193 return (PyObject*)result;
194 }
195
196@@ -476,33 +442,24 @@ GMPy_XMPZ_From_PyIntOrLong(PyObject *obj, CTXT_Object *context)
197 }
198 #endif
199
200- switch (Py_SIZE(templong)) {
201- case -1:
202- mpz_set_si(result->z, -(sdigit)templong->ob_digit[0]);
203+ len = _PyLong_DigitCount(templong);
204+ negative = _PyLong_IsNegative(templong);
205+
206+ switch (len) {
207+ case 1:
208+ mpz_set_si(result->z, (sdigit)GET_OB_DIGIT(templong)[0]);
209 break;
210 case 0:
211 mpz_set_si(result->z, 0);
212 break;
213- case 1:
214- mpz_set_si(result->z, templong->ob_digit[0]);
215- break;
216 default:
217- mpz_set_si(result->z, 0);
218-
219- if (Py_SIZE(templong) < 0) {
220- len = - Py_SIZE(templong);
221- negative = 1;
222- } else {
223- len = Py_SIZE(templong);
224- negative = 0;
225- }
226-
227- mpz_import(result->z, len, -1, sizeof(templong->ob_digit[0]), 0,
228- sizeof(templong->ob_digit[0])*8 - PyLong_SHIFT, templong->ob_digit);
229+ mpz_import(result->z, len, -1, sizeof(GET_OB_DIGIT(templong)[0]), 0,
230+ sizeof(GET_OB_DIGIT(templong)[0])*8 - PyLong_SHIFT,
231+ GET_OB_DIGIT(templong));
232+ }
233
234- if (negative) {
235- mpz_neg(result->z, result->z);
236- }
237+ if (negative) {
238+ mpz_neg(result->z, result->z);
239 }
240 return result;
241 }
242@@ -639,7 +596,7 @@ GMPy_MPQ_From_PyStr(PyObject *s, int base, CTXT_Object *context)
243 }
244
245 cp = PyBytes_AsString(ascii_str);
246-
247+
248 {
249 char *whereslash = strchr((char*)cp, '/');
250 char *wheredot = strchr((char*)cp, '.');
251diff --git a/src/gmpy2_convert_utils.c b/src/gmpy2_convert_utils.c
252index d676eaf..8908d17 100644
253--- a/src/gmpy2_convert_utils.c
254+++ b/src/gmpy2_convert_utils.c
255@@ -123,7 +123,7 @@ static unsigned long
256 GMPy_Integer_AsUnsignedLongWithType_v2(PyObject *x, int xtype)
257 {
258 if IS_TYPE_PyInteger(xtype) {
259- if (Py_SIZE(x) < 0) {
260+ if (_PyLong_IsNegative(((PyLongObject*)x))) {
261 VALUE_ERROR("n must be > 0");
262 return (unsigned long)-1;
263 }