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>,
|
||||
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>`_
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -461,7 +482,7 @@ API example::
|
|||
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
|
||||
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
|
||||
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
|
||||
development, benchmark different variants for exporting small integers (is that
|
||||
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.
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue