PEP 757: mark as Final (#4167)
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
This commit is contained in:
parent
d8194ab32c
commit
cbf8efbc53
|
@ -3,13 +3,16 @@ Title: C API to import-export Python integers
|
||||||
Author: Sergey B Kirpichev <skirpichev@gmail.com>,
|
Author: Sergey B Kirpichev <skirpichev@gmail.com>,
|
||||||
Victor Stinner <vstinner@python.org>
|
Victor Stinner <vstinner@python.org>
|
||||||
Discussions-To: https://discuss.python.org/t/63895
|
Discussions-To: https://discuss.python.org/t/63895
|
||||||
Status: Accepted
|
Status: Final
|
||||||
Type: Standards Track
|
Type: Standards Track
|
||||||
Created: 13-Sep-2024
|
Created: 13-Sep-2024
|
||||||
Python-Version: 3.14
|
Python-Version: 3.14
|
||||||
Post-History: `14-Sep-2024 <https://discuss.python.org/t/63895>`__
|
Post-History: `14-Sep-2024 <https://discuss.python.org/t/63895>`__
|
||||||
Resolution: `08-Dec-2024 <https://discuss.python.org/t/63895/79>`__
|
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>`_
|
||||||
|
|
||||||
.. highlight:: c
|
.. highlight:: c
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,11 +70,13 @@ functions.
|
||||||
|
|
||||||
.. c:member:: uint8_t bits_per_digit
|
.. 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
|
.. 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
|
.. c:member:: int8_t digits_order
|
||||||
|
|
||||||
|
@ -85,7 +90,7 @@ functions.
|
||||||
Digit endianness:
|
Digit endianness:
|
||||||
|
|
||||||
- ``1`` for most significant byte first (big endian)
|
- ``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)
|
.. c:function:: const PyLongLayout* PyLong_GetNativeLayout(void)
|
||||||
|
@ -110,10 +115,8 @@ Export API
|
||||||
There are two cases:
|
There are two cases:
|
||||||
|
|
||||||
* If :c:member:`digits` is ``NULL``, only use the :c:member:`value` member.
|
* 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`,
|
* If :c:member:`digits` is not ``NULL``, use :c:member:`negative`,
|
||||||
:c:member:`ndigits` and :c:member:`digits` members.
|
:c:member:`ndigits` and :c:member:`digits` members.
|
||||||
Calling :c:func:`PyLong_FreeExport` is mandatory in this case.
|
|
||||||
|
|
||||||
.. c:member:: int64_t value
|
.. c:member:: int64_t value
|
||||||
|
|
||||||
|
@ -145,11 +148,17 @@ If :c:member:`PyLongExport.digits` is not ``NULL``, a private field of the
|
||||||
|
|
||||||
Export a Python :class:`int` object.
|
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.
|
On error, set an exception and return -1.
|
||||||
|
|
||||||
If *export_long->digits* is not ``NULL``, :c:func:`PyLong_FreeExport` must be
|
:c:func:`PyLong_FreeExport` must be called when the export is no longer
|
||||||
called when the export is no longer needed.
|
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
|
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.
|
||||||
|
|
||||||
Release the export *export_long* created by :c:func:`PyLong_Export`.
|
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
|
Import API
|
||||||
----------
|
----------
|
||||||
|
|
||||||
The :c:type:`PyLongWriter` API can be used to import an integer:
|
The :c:type:`PyLongWriter` API can be used to import an integer.
|
||||||
create a Python :class:`int` object from a digits array.
|
|
||||||
|
|
||||||
.. c:struct:: PyLongWriter
|
.. c:struct:: PyLongWriter
|
||||||
|
|
||||||
|
@ -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
|
*ndigits* is the number of digits in the *digits* array. It must be
|
||||||
greater than 0.
|
greater than 0.
|
||||||
|
|
||||||
The caller can either initialize the array of digits *digits* and then
|
*digits* must not be NULL.
|
||||||
either call :c:func:`PyLongWriter_Finish` to get a Python :class:`int` or
|
|
||||||
:c:func:`PyLongWriter_Discard` to destroy the writer instance. Digits must
|
After a successful call to this function, the caller should fill in the
|
||||||
be in the range [``0``; ``(1 << bits_per_digit) - 1``] (where the
|
array of digits *digits* and then call :c:func:`PyLongWriter_Finish` to get
|
||||||
:c:struct:`~PyLongLayout.bits_per_digit` is the number of bits per digit).
|
a Python :class:`int`.
|
||||||
The unused most-significant digits must be set to ``0``.
|
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
|
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.
|
||||||
The function takes care of normalizing the digits and converts the
|
The function takes care of normalizing the digits and converts the
|
||||||
object to a compact integer if needed.
|
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)
|
.. c:function:: void PyLongWriter_Discard(PyLongWriter *writer)
|
||||||
|
|
||||||
Discard a :c:type:`PyLongWriter` created by :c:func:`PyLongWriter_Create`.
|
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
|
Optimize import for small integers
|
||||||
|
@ -461,7 +482,7 @@ API example::
|
||||||
This might work for the GMP, as it has :c:func:`!mpz_limbs_read()` and
|
This might work for the GMP, as it has :c:func:`!mpz_limbs_read()` and
|
||||||
:c:func:`!mpz_limbs_write()` functions, that can provide required access to
|
:c:func:`!mpz_limbs_write()` functions, that can provide required access to
|
||||||
internals of :c:struct:`!mpz_t`. Other libraries may require using temporary
|
internals of :c:struct:`!mpz_t`. Other libraries may require using temporary
|
||||||
bufferes and then mpz_import/export-like functions on their side.
|
buffers and then mpz_import/export-like functions on their side.
|
||||||
|
|
||||||
The major drawback of this approach is that it's much more complex on the
|
The major drawback of this approach is that it's much more complex on the
|
||||||
CPython side (i.e. actual conversion between different layouts). For example,
|
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
|
||||||
will be less convenient for end users. They will have to follow Python
|
will be less convenient for end users. They will have to follow Python
|
||||||
development, benchmark different variants for exporting small integers (is that
|
development, benchmark different variants for exporting small integers (is that
|
||||||
obvious why above case was chosen instead of :c:func:`PyLong_AsInt64`?), maybe
|
obvious why above case was chosen instead of :c:func:`PyLong_AsInt64`?), maybe
|
||||||
support different code paths for various CPython versions or accross different
|
support different code paths for various CPython versions or across different
|
||||||
Python implementations.
|
Python implementations.
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue