Skip to content

Commit cbf8efb

Browse files
skirpichevhugovk
andauthored
PEP 757: mark as Final (#4167)
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
1 parent d8194ab commit cbf8efb

File tree

1 file changed

+42
-21
lines changed

1 file changed

+42
-21
lines changed

peps/pep-0757.rst

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ Title: C API to import-export Python integers
33
Author: Sergey B Kirpichev <skirpichev@gmail.com>,
44
Victor Stinner <vstinner@python.org>
55
Discussions-To: https://discuss.python.org/t/63895
6-
Status: Accepted
6+
Status: Final
77
Type: Standards Track
88
Created: 13-Sep-2024
99
Python-Version: 3.14
1010
Post-History: `14-Sep-2024 <https://discuss.python.org/t/63895>`__
1111
Resolution: `08-Dec-2024 <https://discuss.python.org/t/63895/79>`__
1212

13+
14+
.. canonical-doc:: the `Export API <https://docs.python.org/dev/c-api/long.html#export-api>`_ and the `PyLongWriter API <https://docs.python.org/dev/c-api/long.html#pylongwriter-api>`_
15+
1316
.. highlight:: c
1417

1518

@@ -67,11 +70,13 @@ functions.
6770

6871
.. c:member:: uint8_t bits_per_digit
6972
70-
Bits per digit.
73+
Bits per digit. For example, a 15 bit digit means that bits 0-14
74+
contain meaningful information.
7175

7276
.. c:member:: uint8_t digit_size
7377
74-
Digit size in bytes.
78+
Digit size in bytes. For example, a 15 bit digit will require at least
79+
2 bytes.
7580

7681
.. c:member:: int8_t digits_order
7782
@@ -85,7 +90,7 @@ functions.
8590
Digit endianness:
8691

8792
- ``1`` for most significant byte first (big endian)
88-
- ``-1`` for least significant first (little endian)
93+
- ``-1`` for least significant byte first (little endian)
8994

9095

9196
.. c:function:: const PyLongLayout* PyLong_GetNativeLayout(void)
@@ -110,10 +115,8 @@ Export API
110115
There are two cases:
111116
112117
* If :c:member:`digits` is ``NULL``, only use the :c:member:`value` member.
113-
Calling :c:func:`PyLong_FreeExport` is optional in this case.
114118
* If :c:member:`digits` is not ``NULL``, use :c:member:`negative`,
115119
:c:member:`ndigits` and :c:member:`digits` members.
116-
Calling :c:func:`PyLong_FreeExport` is mandatory in this case.
117120
118121
.. c:member:: int64_t value
119122
@@ -145,11 +148,17 @@ If :c:member:`PyLongExport.digits` is not ``NULL``, a private field of the
145148
146149
Export a Python :class:`int` object.
147150
148-
On success, set *\*export_long* and return 0.
151+
*export_long* must point to a :c:struct:`PyLongExport` structure allocated
152+
by the caller. It must not be ``NULL``.
153+
154+
On success, fill in *\*export_long* and return 0.
149155
On error, set an exception and return -1.
150156
151-
If *export_long->digits* is not ``NULL``, :c:func:`PyLong_FreeExport` must be
152-
called when the export is no longer needed.
157+
:c:func:`PyLong_FreeExport` must be called when the export is no longer
158+
needed.
159+
160+
**CPython implementation detail**: This function always succeeds if *obj* is
161+
a Python :class:`int` object or a subclass.
153162
154163
155164
On CPython 3.14, no memory copy is needed in :c:func:`PyLong_Export`, it's just
@@ -160,12 +169,14 @@ a thin wrapper to expose Python :class:`int` internal digits array.
160169
161170
Release the export *export_long* created by :c:func:`PyLong_Export`.
162171
172+
**CPython implementation detail**: Calling :c:func:`PyLong_FreeExport` is
173+
optional if *export_long->digits* is ``NULL``.
174+
163175
164176
Import API
165177
----------
166178
167-
The :c:type:`PyLongWriter` API can be used to import an integer:
168-
create a Python :class:`int` object from a digits array.
179+
The :c:type:`PyLongWriter` API can be used to import an integer.
169180
170181
.. c:struct:: PyLongWriter
171182
@@ -187,12 +198,20 @@ create a Python :class:`int` object from a digits array.
187198
*ndigits* is the number of digits in the *digits* array. It must be
188199
greater than 0.
189200
190-
The caller can either initialize the array of digits *digits* and then
191-
either call :c:func:`PyLongWriter_Finish` to get a Python :class:`int` or
192-
:c:func:`PyLongWriter_Discard` to destroy the writer instance. Digits must
193-
be in the range [``0``; ``(1 << bits_per_digit) - 1``] (where the
194-
:c:struct:`~PyLongLayout.bits_per_digit` is the number of bits per digit).
195-
The unused most-significant digits must be set to ``0``.
201+
*digits* must not be NULL.
202+
203+
After a successful call to this function, the caller should fill in the
204+
array of digits *digits* and then call :c:func:`PyLongWriter_Finish` to get
205+
a Python :class:`int`.
206+
The layout of *digits* is described by :c:func:`PyLong_GetNativeLayout`.
207+
208+
Digits must be in the range [``0``; ``(1 << bits_per_digit) - 1``]
209+
(where the :c:struct:`~PyLongLayout.bits_per_digit` is the number of bits
210+
per digit).
211+
Any unused most significant digits must be set to ``0``.
212+
213+
Alternately, call :c:func:`PyLongWriter_Discard` to destroy the writer
214+
instance without creating an :class:`~int` object.
196215
197216
198217
On CPython 3.14, the :c:func:`PyLongWriter_Create` implementation is a thin
@@ -209,14 +228,16 @@ wrapper to the private :c:func:`!_PyLong_New()` function.
209228
The function takes care of normalizing the digits and converts the
210229
object to a compact integer if needed.
211230
212-
The writer instance is invalid after the call.
231+
The writer instance and the *digits* array are invalid after the call.
213232
214233
215234
.. c:function:: void PyLongWriter_Discard(PyLongWriter *writer)
216235
217236
Discard a :c:type:`PyLongWriter` created by :c:func:`PyLongWriter_Create`.
218237
219-
The writer instance is invalid after the call.
238+
*writer* must not be ``NULL``.
239+
240+
The writer instance and the *digits* array are invalid after the call.
220241
221242
222243
Optimize import for small integers
@@ -461,7 +482,7 @@ API example::
461482
This might work for the GMP, as it has :c:func:`!mpz_limbs_read()` and
462483
:c:func:`!mpz_limbs_write()` functions, that can provide required access to
463484
internals of :c:struct:`!mpz_t`. Other libraries may require using temporary
464-
bufferes and then mpz_import/export-like functions on their side.
485+
buffers and then mpz_import/export-like functions on their side.
465486
466487
The major drawback of this approach is that it's much more complex on the
467488
CPython side (i.e. actual conversion between different layouts). For example,
@@ -532,7 +553,7 @@ This might look as a simplification from the API designer point of view, but
532553
will be less convenient for end users. They will have to follow Python
533554
development, benchmark different variants for exporting small integers (is that
534555
obvious why above case was chosen instead of :c:func:`PyLong_AsInt64`?), maybe
535-
support different code paths for various CPython versions or accross different
556+
support different code paths for various CPython versions or across different
536557
Python implementations.
537558
538559

0 commit comments

Comments
 (0)