@@ -129,6 +129,11 @@ Export API
129
129
130
130
Read-only array of unsigned digits. Can be ``NULL``.
131
131
132
+ If :c:member:`digits` not ``NULL``, a private field of the
133
+ :c:struct:`PyLongExport` structure stores a strong reference to the Python
134
+ :class:`int` object to make sure that that structure remains valid until
135
+ :c:func:`PyLong_FreeExport()` is called.
136
+
132
137
133
138
.. c:function:: int PyLong_Export(PyObject *obj, PyLongExport *export_long)
134
139
@@ -146,11 +151,6 @@ Export API
146
151
On CPython 3.14, no memory copy is needed, it's just a thin wrapper to
147
152
expose Python int internal digits array.
148
153
149
- If :c:member: `~PyLongExport.digits ` not ``NULL ``, a private field of
150
- the :c:struct: `PyLongExport ` structure stores a strong reference to
151
- the Python :class: `int ` object to make sure that that structure
152
- remains valid until :c:func: `PyLong_FreeExport() ` is called.
153
-
154
154
155
155
.. c :function :: void PyLong_FreeExport (PyLongExport *export_long)
156
156
@@ -183,9 +183,9 @@ create a Python :class:`int` object from a digits array.
183
183
greater than or equal to 0.
184
184
185
185
The caller must initialize the array of digits *digits * and then call
186
- :c:func: `PyLongWriter_Finish ` to get a Python :class: `int `. Digits must be
187
- in the range [``0 ``; ``PyLong_BASE - 1 ``]. Unused digits must be set to
188
- ``0 ``.
186
+ :c:func: `PyLongWriter_Finish ` to get a Python :class: `int `. Digits must be
187
+ in the range [``0 ``; ``(1 << sys.int_info.bits_per_digit) - 1 ``]. Unused digits must
188
+ be set to ``0 ``.
189
189
190
190
On CPython 3.14, the implementation is a thin wrapper to the private
191
191
:c:func: `!_PyLong_New() ` function.
@@ -238,6 +238,18 @@ Implementation
238
238
Benchmarks
239
239
==========
240
240
241
+ Code::
242
+
243
+ /* Query parameters of Python’s internal representation of integers. */
244
+ const PyLongLayout *layout = PyLong_GetNativeLayout();
245
+
246
+ size_t int_digit_size = layout->digit_size;
247
+ int int_digits_order = layout->digits_order;
248
+ size_t int_bits_per_digit = layout->bits_per_digit;
249
+ size_t int_nails = int_digit_size*8 - int_bits_per_digit;
250
+ int int_endianness = layout->endianness;
251
+
252
+
241
253
Export: :c:func: `PyLong_Export() ` with gmpy2
242
254
--------------------------------------------
243
255
@@ -246,28 +258,26 @@ Code::
246
258
static void
247
259
mpz_set_PyLong(mpz_t z, PyObject *obj)
248
260
{
249
- const PyLongLayout* layout = PyLong_GetNativeLayout();
250
261
static PyLongExport long_export;
251
262
252
263
PyLong_Export(obj, &long_export);
253
264
if (long_export.digits) {
254
- mpz_import(z, long_export.ndigits, layout->digits_order,
255
- layout->digit_size, layout->endianness,
256
- layout->digit_size*8 - layout->bits_per_digit,
257
- long_export.digits);
265
+ mpz_import(z, long_export.ndigits, int_digits_order, int_digit_size,
266
+ int_endianness, int_nails, long_export.digits);
258
267
if (long_export.negative) {
259
268
mpz_neg(z, z);
260
269
}
261
270
PyLong_FreeExport(&long_export);
262
271
}
263
272
else {
264
- if (LONG_MIN <= long_export.value && long_export.value <= LONG_MAX) {
265
- mpz_set_si(z, long_export.value);
273
+ const int64_t value = long_export.value;
274
+
275
+ if (LONG_MIN <= value && value <= LONG_MAX) {
276
+ mpz_set_si(z, value);
266
277
}
267
278
else {
268
- mpz_import(z, 1, -1, sizeof(int64_t), 0, 0,
269
- &long_export.value);
270
- if (long_export.value < 0) {
279
+ mpz_import(z, 1, -1, sizeof(int64_t), 0, 0, &value);
280
+ if (value < 0) {
271
281
mpz_t tmp;
272
282
mpz_init(tmp);
273
283
mpz_ui_pow_ui(tmp, 2, 64);
@@ -324,20 +334,17 @@ Code::
324
334
return PyLong_FromLong(mpz_get_si(obj->z));
325
335
}
326
336
327
- const PyLongLayout *layout = PyLong_GetNativeLayout();
328
337
size_t size = (mpz_sizeinbase(obj->z, 2) +
329
- layout->bits_per_digit - 1) / layout->bits_per_digit ;
338
+ int_bits_per_digit - 1) / int_bits_per_digit ;
330
339
void *digits;
331
340
PyLongWriter *writer = PyLongWriter_Create(mpz_sgn(obj->z) < 0, size,
332
341
&digits);
333
342
if (writer == NULL) {
334
343
return NULL;
335
344
}
336
345
337
- mpz_export(digits, NULL, layout->endianness,
338
- layout->digit_size, layout->digits_order,
339
- layout->digit_size*8 - layout->bits_per_digit,
340
- obj->z);
346
+ mpz_export(digits, NULL, int_digits_order, int_digit_size,
347
+ int_endianness, int_nails, obj->z);
341
348
342
349
return PyLongWriter_Finish(writer);
343
350
}
@@ -389,11 +396,11 @@ Open Questions
389
396
:c:func:`PyLong_GetNativeLayout()` function returns a C structure
390
397
which is more convenient to use in C than :data:`sys.int_info` which uses
391
398
Python objects.
392
- * Currenly , all required information for :class:`int` import/export is
399
+ * Currently , all required information for :class:`int` import/export is
393
400
already available via :c:func:`PyLong_GetInfo()` or :data:`sys.int_info`.
394
401
Native endianness of "digits" and current order of digits (least
395
402
significant digit first) --- is a common denominator of all libraries
396
- for aribitrary precision integer arithmetic. So, shouldn't we just remove
403
+ for arbitrary precision integer arithmetic. So, shouldn't we just remove
397
404
from API both :c:struct:`PyLongLayout` and :c:func:`PyLong_GetNativeLayout()` (which
398
405
is actually just a minor convenience)?
399
406
0 commit comments