@@ -3,13 +3,16 @@ Title: C API to import-export Python integers
33Author: Sergey B Kirpichev <skirpichev@gmail.com>,
44 Victor Stinner <vstinner@python.org>
55Discussions-To: https://discuss.python.org/t/63895
6- Status: Accepted
6+ Status: Final
77Type: Standards Track
88Created: 13-Sep-2024
99Python-Version: 3.14
1010Post-History: `14-Sep-2024 <https://discuss.python.org/t/63895 >`__
1111Resolution: `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
155164On 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
164176Import 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
198217On 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
222243Optimize import for small integers
@@ -461,7 +482,7 @@ API example::
461482This 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
463484internals 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
466487The major drawback of this approach is that it's much more complex on the
467488CPython 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
532553will be less convenient for end users. They will have to follow Python
533554development, benchmark different variants for exporting small integers (is that
534555obvious 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
536557Python implementations.
537558
538559
0 commit comments