@@ -63,10 +63,10 @@ API::
63
63
// * -1 for least significant digit first
64
64
int8_t digits_order;
65
65
66
- // Endian :
66
+ // Endianness :
67
67
// * 1 for most significant byte first (big endian)
68
68
// * -1 for least significant byte first (little endian)
69
- int8_t endian ;
69
+ int8_t endianness ;
70
70
} PyLongLayout;
71
71
72
72
PyAPI_FUNC(const PyLongLayout*) PyLong_GetNativeLayout(void);
82
82
83
83
Get the native layout of Python :class: `int ` objects.
84
84
85
+ The function must not be called before Python initialization nor after
86
+ Python finalization. The returned layout is valid until Python is
87
+ finalized. The layout is the same for all Python sub-interpreters and
88
+ so it can be cached.
89
+
85
90
86
91
Export API
87
92
----------
@@ -106,6 +111,7 @@ Export a Python integer as a digits array::
106
111
} PyLongExport;
107
112
108
113
int PyLong_Export(PyObject *obj, PyLongExport *array);
114
+ void PyLong_FreeExport(PyLongExport *array);
109
115
110
116
On CPython 3.14, no memory copy is needed, it's just a thin wrapper to
111
117
expose Python int internal digits array.
@@ -215,21 +221,19 @@ API::
215
221
Discard the internal object and destroy the writer instance.
216
222
217
223
218
- Optimize small integers
219
- =======================
224
+ Optimize import for small integers
225
+ ==================================
220
226
221
- Proposed API are efficient for large integers. Compared to accessing
222
- directly Python internals, the proposed API can have a significant
223
- performance overhead on small integers.
227
+ Proposed import API is efficient for large integers. Compared to
228
+ accessing directly Python internals, the proposed import API can have a
229
+ significant performance overhead on small integers.
224
230
225
231
For small integers of a few digits (for example, 1 or 2 digits), existing APIs
226
- can be used
232
+ can be used:
227
233
228
- * :external+py3.14:c:func: `PyLong_FromUInt64() ` / :external+py3.14:c:func: `PyLong_AsUInt64() `;
229
- * :c:func: `PyLong_FromLong() ` / :c:func: `PyLong_AsLong() ` or :c:func: `PyLong_AsInt() `;
230
- * :external+py3.13:c:func: `PyUnstable_Long_IsCompact() ` and
231
- :external+py3.13:c:func: `PyUnstable_Long_CompactValue() `;
232
- * :c:func: `PyLong_FromNativeBytes() ` / :c:func: `PyLong_AsNativeBytes() `;
234
+ * :external+py3.14:c:func: `PyLong_FromUInt64() `;
235
+ * :c:func: `PyLong_FromLong() `;
236
+ * :c:func: `PyLong_FromNativeBytes() `.
233
237
234
238
235
239
Implementation
@@ -262,7 +266,7 @@ Code::
262
266
PyLong_Export(obj, &long_export);
263
267
if (long_export.digits) {
264
268
mpz_import(z, long_export.ndigits, layout->digits_order,
265
- layout->digit_size, layout->endian ,
269
+ layout->digit_size, layout->endianness ,
266
270
layout->digit_size*8 - layout->bits_per_digit,
267
271
long_export.digits);
268
272
if (long_export.negative) {
@@ -307,15 +311,15 @@ mode:
307
311
+----------------+---------+-----------------------+
308
312
| Benchmark | ref | pep757 |
309
313
+================+=========+=======================+
310
- | 1<<7 | 94 .3 ns | 96.8 ns: 1.03x slower |
314
+ | 1<<7 | 91 .3 ns | 89.9 ns: 1.02x faster |
311
315
+----------------+---------+-----------------------+
312
- | 1<<38 | 127 ns | 99.7 ns: 1.28x faster |
316
+ | 1<<38 | 120 ns | 94.9 ns: 1.27x faster |
313
317
+----------------+---------+-----------------------+
314
- | 1<<300 | 209 ns | 222 ns: 1.06x slower |
318
+ | 1<<300 | 196 ns | 203 ns: 1.04x slower |
315
319
+----------------+---------+-----------------------+
316
- | 1<<3000 | 955 ns | 963 ns: 1.01x slower |
320
+ | 1<<3000 | 939 ns | 945 ns: 1.01x slower |
317
321
+----------------+---------+-----------------------+
318
- | Geometric mean | (ref) | 1.04x faster |
322
+ | Geometric mean | (ref) | 1.05x faster |
319
323
+----------------+---------+-----------------------+
320
324
321
325
@@ -341,7 +345,7 @@ Code::
341
345
return NULL;
342
346
}
343
347
344
- mpz_export(digits, NULL, layout->endian ,
348
+ mpz_export(digits, NULL, layout->endianness ,
345
349
layout->digit_size, layout->digits_order,
346
350
layout->digit_size*8 - layout->bits_per_digit,
347
351
obj->z);
@@ -365,17 +369,17 @@ Benchmark:
365
369
Results on Linux Fedora 40 with CPU isolation, Python built in release
366
370
mode:
367
371
368
- +----------------+--------+ ----------------------+
369
- | Benchmark | ref | pep757 |
370
- +================+========+ ======================+
371
- | 1<<300 | 193 ns | 215 ns: 1.11x slower |
372
- +----------------+--------+ ----------------------+
373
- | 1<<3000 | 927 ns | 943 ns: 1.02x slower |
374
- +----------------+--------+ ----------------------+
375
- | Geometric mean | (ref) | 1.03x slower |
376
- +----------------+--------+ ----------------------+
372
+ +----------------+---------+- ----------------------+
373
+ | Benchmark | ref | pep757 |
374
+ +================+=========+= ======================+
375
+ | 1<<7 | 56.7 ns | 56.2 ns: 1.01x faster |
376
+ +----------------+---------+- ----------------------+
377
+ | 1<<300 | 191 ns | 213 ns: 1.12x slower |
378
+ +----------------+---------+- ----------------------+
379
+ | Geometric mean | (ref) | 1.03x slower |
380
+ +----------------+---------+- ----------------------+
377
381
378
- Benchmark hidden because not significant (2): 1<<7 , 1<<38 .
382
+ Benchmark hidden because not significant (2): 1<<38 , 1<<3000 .
379
383
380
384
381
385
Backwards Compatibility
@@ -388,7 +392,7 @@ added.
388
392
Open Questions
389
393
==============
390
394
391
- * Should we add *digits_order * and *endian * members to :data: `sys.int_info `
395
+ * Should we add *digits_order * and *endianness * members to :data: `sys.int_info `
392
396
and remove ``PyLong_GetNativeLayout() ``? The
393
397
``PyLong_GetNativeLayout() `` function returns a C structure
394
398
which is more convenient to use in C than :data: `sys.int_info ` which uses
0 commit comments