Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PEP 757: mark as Final #4167

Merged
merged 10 commits into from
Dec 16, 2024
59 changes: 40 additions & 19 deletions peps/pep-0757.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ Title: C API to import-export Python integers
Author: Sergey B Kirpichev <skirpichev@gmail.com>,
Victor Stinner <vstinner@python.org>
Discussions-To: https://discuss.python.org/t/63895
Status: Accepted
Status: Final
Type: Standards Track
Created: 13-Sep-2024
Python-Version: 3.14
Post-History: `14-Sep-2024 <https://discuss.python.org/t/63895>`__
Resolution: `08-Dec-2024 <https://discuss.python.org/t/63895/79>`__


.. 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>`_
skirpichev marked this conversation as resolved.
Show resolved Hide resolved

.. highlight:: c


Expand Down Expand Up @@ -67,11 +70,13 @@ functions.

.. c:member:: uint8_t bits_per_digit

Bits per digit.
Bits per digit. For example, a 15 bit digit means that bits 0-14
contain meaningful information.

.. c:member:: uint8_t digit_size

Digit size in bytes.
Digit size in bytes. For example, a 15 bit digit will require at least
2 bytes.

.. c:member:: int8_t digits_order

Expand All @@ -85,7 +90,7 @@ functions.
Digit endianness:

- ``1`` for most significant byte first (big endian)
- ``-1`` for least significant first (little endian)
- ``-1`` for least significant byte first (little endian)


.. c:function:: const PyLongLayout* PyLong_GetNativeLayout(void)
Expand All @@ -110,10 +115,8 @@ Export API
There are two cases:

* If :c:member:`digits` is ``NULL``, only use the :c:member:`value` member.
Calling :c:func:`PyLong_FreeExport` is optional in this case.
* If :c:member:`digits` is not ``NULL``, use :c:member:`negative`,
:c:member:`ndigits` and :c:member:`digits` members.
Calling :c:func:`PyLong_FreeExport` is mandatory in this case.

.. c:member:: int64_t value

Expand Down Expand Up @@ -145,11 +148,17 @@ If :c:member:`PyLongExport.digits` is not ``NULL``, a private field of the

Export a Python :class:`int` object.

On success, set *\*export_long* and return 0.
*export_long* must point to a :c:struct:`PyLongExport` structure allocated
by the caller. It must not be ``NULL``.

On success, fill in *\*export_long* and return 0.
On error, set an exception and return -1.

If *export_long->digits* is not ``NULL``, :c:func:`PyLong_FreeExport` must be
called when the export is no longer needed.
:c:func:`PyLong_FreeExport` must be called when the export is no longer
needed.

**CPython implementation detail**: This function always succeeds if *obj* is
a Python :class:`int` object or a subclass.


On CPython 3.14, no memory copy is needed in :c:func:`PyLong_Export`, it's just
Expand All @@ -160,12 +169,14 @@ a thin wrapper to expose Python :class:`int` internal digits array.

Release the export *export_long* created by :c:func:`PyLong_Export`.

**CPython implementation detail**: Calling :c:func:`PyLong_FreeExport` is
optional if *export_long->digits* is ``NULL``.


Import API
----------

The :c:type:`PyLongWriter` API can be used to import an integer:
create a Python :class:`int` object from a digits array.
The :c:type:`PyLongWriter` API can be used to import an integer.

.. c:struct:: PyLongWriter

Expand All @@ -187,12 +198,20 @@ create a Python :class:`int` object from a digits array.
*ndigits* is the number of digits in the *digits* array. It must be
greater than 0.

The caller can either initialize the array of digits *digits* and then
either call :c:func:`PyLongWriter_Finish` to get a Python :class:`int` or
:c:func:`PyLongWriter_Discard` to destroy the writer instance. Digits must
be in the range [``0``; ``(1 << bits_per_digit) - 1``] (where the
:c:struct:`~PyLongLayout.bits_per_digit` is the number of bits per digit).
The unused most-significant digits must be set to ``0``.
*digits* must not be NULL.

After a successful call to this function, the caller should fill in the
array of digits *digits* and then call :c:func:`PyLongWriter_Finish` to get
a Python :class:`int`.
The layout of *digits* is described by :c:func:`PyLong_GetNativeLayout`.

Digits must be in the range [``0``; ``(1 << bits_per_digit) - 1``]
(where the :c:struct:`~PyLongLayout.bits_per_digit` is the number of bits
per digit).
Any unused most significant digits must be set to ``0``.

Alternately, call :c:func:`PyLongWriter_Discard` to destroy the writer
instance without creating an :class:`~int` object.


On CPython 3.14, the :c:func:`PyLongWriter_Create` implementation is a thin
Expand All @@ -209,14 +228,16 @@ wrapper to the private :c:func:`!_PyLong_New()` function.
The function takes care of normalizing the digits and converts the
object to a compact integer if needed.

The writer instance is invalid after the call.
The writer instance and the *digits* array are invalid after the call.


.. c:function:: void PyLongWriter_Discard(PyLongWriter *writer)

Discard a :c:type:`PyLongWriter` created by :c:func:`PyLongWriter_Create`.

The writer instance is invalid after the call.
*writer* must not be ``NULL``.

The writer instance and the *digits* array are invalid after the call.


Optimize import for small integers
Expand Down
Loading