Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit21dd5b9

Browse files
committed
gh-102471: Add PyLong import and export API
Add PyLong_Export() and PyLong_Import() functions and PyLong_LAYOUTstructure.
1 parent722229e commit21dd5b9

File tree

8 files changed

+391
-1
lines changed

8 files changed

+391
-1
lines changed

‎Doc/c-api/long.rst‎

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,10 +529,118 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
529529
Exactly what values are considered compact is an implementation detail
530530
and is subject to change.
531531
532+
..versionadded::3.12
533+
534+
532535
..c:function:: Py_ssize_tPyUnstable_Long_CompactValue(const PyLongObject* op)
533536
534537
If *op* is compact, as determined by :c:func:`PyUnstable_Long_IsCompact`,
535538
return its value.
536539
537540
Otherwise, the return value is undefined.
538541
542+
.. versionadded:: 3.12
543+
544+
545+
Import/Export API
546+
^^^^^^^^^^^^^^^^^
547+
548+
.. versionadded:: 3.14
549+
550+
.. c:type:: Py_digit
551+
552+
A single unsigned digit.
553+
554+
It is usually used in an *array of digits*, such as the
555+
:c:member:`PyUnstable_LongExport.digits` array.
556+
557+
Its size depend on the :c:macro:`PYLONG_BITS_IN_DIGIT` macro:
558+
see the ``configure`` :option:`--enable-big-digits` option.
559+
560+
See :c:member:`PyUnstable_Long_LAYOUT.bits_per_digit` for the number of bits per
561+
digit and :c:member:`PyUnstable_Long_LAYOUT.digit_size` for the size of a digit (in
562+
bytes).
563+
564+
565+
.. c:struct:: PyUnstable_Long_LAYOUT
566+
567+
Internal layout of a Python :class:`int` object.
568+
569+
See also :attr:`sys.int_info` which exposes similar information to Python.
570+
571+
.. c:member:: uint8_t bits_per_digit;
572+
573+
Bits per digit.
574+
575+
..c:member::uint8_t digit_size;
576+
577+
Digit size in bytes.
578+
579+
..c:member::int8_t word_endian;
580+
581+
Word endian:
582+
583+
- 1 for most significant byte first (big endian)
584+
- 0 for least significant first (little endian)
585+
586+
.. c:member:: int8_t array_endian;
587+
588+
Array endian:
589+
590+
-1for most significant bytefirst (big endian)
591+
- 0 for least significant first (little endian)
592+
593+
594+
.. c:function:: PyObject* PyUnstable_Long_Import(int negative, size_t ndigits, Py_digit *digits)
595+
596+
Create a Python:class:`int` object from an array of digits.
597+
598+
* Return a Python:class:`int` object on success.
599+
* Set an exception and return ``NULL`` on error.
600+
601+
*negative* is ``1`` if the number is negative, or ``0`` otherwise.
602+
603+
*ndigits* is the number of digits in the *digits* array.
604+
605+
*digits* is an array of unsigned digits.
606+
607+
See:c:struct:`PyUnstable_Long_LAYOUT` for the internal layout of an integer.
608+
609+
610+
..c:struct:: PyUnstable_LongExport
611+
612+
A Python:class:`int` object exported as an array of digits.
613+
614+
See:c:struct:`PyUnstable_Long_LAYOUT` for the internal layout of an integer.
615+
616+
..c:member:: PyLongObject *obj
617+
618+
Strong reference to the Python:class:`int` object.
619+
620+
..c:member::int negative
621+
622+
1 if the number is negative, 0 otherwise.
623+
624+
..c:member::size_t ndigits
625+
626+
Number of digits in:c:member:`digits` array.
627+
628+
..c:member:: Py_digit *digits
629+
630+
Array of unsigned digits.
631+
632+
633+
..c:function::intPyUnstable_Long_Export(PyLongObject *obj, PyUnstable_LongExport *export)
634+
635+
Export a Python:class:`int` object as an array of digits.
636+
637+
* Set *\*export* and return 0 on success.
638+
* Set an exception and return -1 on error.
639+
640+
:c:func:`PyUnstable_Long_ReleaseExport` must be called once done with using
641+
*export*.
642+
643+
644+
..c:function::voidPyUnstable_Long_ReleaseExport(PyUnstable_LongExport *export)
645+
646+
Release an export created by:c:func:`PyUnstable_Long_Export`.

‎Doc/using/configure.rst‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ General Options
129129

130130
Define the ``PYLONG_BITS_IN_DIGIT`` to ``15`` or ``30``.
131131

132-
See:data:`sys.int_info.bits_per_digit <sys.int_info>`.
132+
See:data:`sys.int_info.bits_per_digit <sys.int_info>` and the
133+
:c:type:`Py_digit` type.
133134

134135
..option::--with-suffix=SUFFIX
135136

‎Doc/whatsnew/3.14.rst‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,14 @@ New Features
343343

344344
(Contributed by Victor Stinner in:gh:`119182`.)
345345

346+
* Add a new unstable import and export API for Python:class:`int` objects:
347+
348+
*:c:func:`PyUnstable_Long_Import`;
349+
*:c:func:`PyUnstable_Long_Export`;
350+
*:c:struct:`PyUnstable_Long_LAYOUT`.
351+
352+
(Contributed by Victor Stinner in:gh:`102471`.)
353+
346354
Porting to Python 3.14
347355
----------------------
348356

‎Include/cpython/longintrepr.h‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ typedef long stwodigits; /* signed variant of twodigits */
6161
#definePyLong_BASE ((digit)1 << PyLong_SHIFT)
6262
#definePyLong_MASK ((digit)(PyLong_BASE - 1))
6363

64+
typedefdigitPy_digit;
65+
6466
/* Long integer representation.
6567
6668
Long integers are made up of a number of 30- or 15-bit digits, depending on
@@ -139,6 +141,43 @@ _PyLong_CompactValue(PyLongObject *op)
139141
#definePyUnstable_Long_CompactValue _PyLong_CompactValue
140142

141143

144+
/* --- Import/Export API -------------------------------------------------- */
145+
146+
typedefstructPyUnstable_LongLayout {
147+
// Bits per digit
148+
uint8_tbits_per_digit;
149+
150+
// Digit size in bytes: sizeof(digit)
151+
uint8_tdigit_size;
152+
153+
// Word endian:
154+
// - 1 for most significant byte first (big endian)
155+
// - 0 for least significant first (little endian)
156+
int8_tword_endian;
157+
158+
// Array endian:
159+
// - 1 for most significant byte first (big endian)
160+
// - 0 for least significant first (little endian)
161+
int8_tarray_endian;
162+
}PyUnstable_LongLayout;
163+
164+
PyAPI_DATA(constPyUnstable_LongLayout)PyUnstable_Long_LAYOUT;
165+
166+
PyAPI_FUNC(PyObject*)PyUnstable_Long_Import(
167+
intnegative,
168+
size_tndigits,
169+
Py_digit*digits);
170+
171+
typedefstructPyUnstable_LongExport {
172+
PyLongObject*obj;
173+
intnegative;
174+
size_tndigits;
175+
Py_digit*digits;
176+
}PyUnstable_LongExport;
177+
178+
PyAPI_FUNC(int)PyUnstable_Long_Export(PyLongObject*obj,PyUnstable_LongExport*export);
179+
PyAPI_FUNC(void)PyUnstable_Long_ReleaseExport(PyUnstable_LongExport*export);
180+
142181
#ifdef__cplusplus
143182
}
144183
#endif

‎Lib/test/test_capi/test_long.py‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,50 @@ def test_long_getsign(self):
744744

745745
# CRASHES getsign(NULL)
746746

747+
deftest_long_layout(self):
748+
# Test PyLong_LAYOUT
749+
int_info=sys.int_info
750+
layout=_testcapi.get_pylong_layout()
751+
expected= {
752+
'array_endian':0,
753+
'bits_per_digit':int_info.bits_per_digit,
754+
'digit_size':int_info.sizeof_digit,
755+
'word_endian':1ifsys.byteorder=='little'else0,
756+
}
757+
self.assertEqual(layout,expected)
758+
759+
deftest_long_export(self):
760+
# Test PyLong_Export()
761+
layout=_testcapi.get_pylong_layout()
762+
shift=2**layout['bits_per_digit']
763+
764+
pylong_export=_testcapi.pylong_export
765+
self.assertEqual(pylong_export(0), (0, [0]))
766+
self.assertEqual(pylong_export(123), (0, [123]))
767+
self.assertEqual(pylong_export(-123), (1, [123]))
768+
self.assertEqual(pylong_export(shift**2*3+shift*2+1),
769+
(0, [1,2,3]))
770+
771+
deftest_long_import(self):
772+
# Test PyLong_Import()
773+
layout=_testcapi.get_pylong_layout()
774+
shift=2**layout['bits_per_digit']
775+
776+
pylong_import=_testcapi.pylong_import
777+
self.assertEqual(pylong_import(0, [0]),0)
778+
self.assertEqual(pylong_import(0, [123]),123)
779+
self.assertEqual(pylong_import(1, [123]),-123)
780+
self.assertEqual(pylong_import(0, [1,2,3]),
781+
shift**2*3+shift*2+1)
782+
783+
# round trip: Python int -> export -> Python int
784+
pylong_export=_testcapi.pylong_export
785+
numbers= [*range(0,10),12345,0xdeadbeef,2**100,2**100-1]
786+
numbers.extend(-numfornuminlist(numbers))
787+
fornuminnumbers:
788+
withself.subTest(num=num):
789+
export=pylong_export(num)
790+
self.assertEqual(pylong_import(*export),num,export)
747791

748792
if__name__=="__main__":
749793
unittest.main()
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Add a new unstable import and export API for Python:class:`int` objects:
2+
3+
*:c:func:`PyUnstable_Long_Import`;
4+
*:c:func:`PyUnstable_Long_Export`;
5+
*:c:struct:`PyUnstable_Long_LAYOUT`.
6+
7+
Patch by Victor Stinner.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp