summaryrefslogtreecommitdiffstats
path: root/Doc
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2024-12-13 13:24:48 (GMT)
committerGitHub <noreply@github.com>2024-12-13 13:24:48 (GMT)
commit6446408d426814bf2bc9d3911a91741f04d4bc4e (patch)
tree2da74eda8cbf6b90d3fefe09378374d1c1b354bc /Doc
parentd05a4e6a0d366b854a3103cae0c941811fd48c4c (diff)
downloadcpython-6446408d426814bf2bc9d3911a91741f04d4bc4e.zip
cpython-6446408d426814bf2bc9d3911a91741f04d4bc4e.tar.gz
cpython-6446408d426814bf2bc9d3911a91741f04d4bc4e.tar.bz2
gh-102471, PEP 757: Add PyLong import and export API (#121339)
Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com> Co-authored-by: Steve Dower <steve.dower@microsoft.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Diffstat (limited to 'Doc')
-rw-r--r--Doc/c-api/long.rst174
-rw-r--r--Doc/data/refcounts.dat7
-rw-r--r--Doc/whatsnew/3.14.rst11
3 files changed, 192 insertions, 0 deletions
diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst
index cb12d43..f48cd07 100644
--- a/Doc/c-api/long.rst
+++ b/Doc/c-api/long.rst
@@ -653,3 +653,177 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
.. versionadded:: 3.12
+
+Export API
+^^^^^^^^^^
+
+.. versionadded:: next
+
+.. c:struct:: PyLongLayout
+
+ Layout of an array of "digits" ("limbs" in the GMP terminology), used to
+ represent absolute value for arbitrary precision integers.
+
+ Use :c:func:`PyLong_GetNativeLayout` to get the native layout of Python
+ :class:`int` objects, used internally for integers with "big enough"
+ absolute value.
+
+ See also :data:`sys.int_info` which exposes similar information in Python.
+
+ .. c:member:: uint8_t 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. For example, a 15 bit digit will require at least 2
+ bytes.
+
+ .. c:member:: int8_t digits_order
+
+ Digits order:
+
+ - ``1`` for most significant digit first
+ - ``-1`` for least significant digit first
+
+ .. c:member:: int8_t digit_endianness
+
+ Digit endianness:
+
+ - ``1`` for most significant byte first (big endian)
+ - ``-1`` for least significant byte first (little endian)
+
+
+.. c:function:: const PyLongLayout* PyLong_GetNativeLayout(void)
+
+ Get the native layout of Python :class:`int` objects.
+
+ See the :c:struct:`PyLongLayout` structure.
+
+ The function must not be called before Python initialization nor after
+ Python finalization. The returned layout is valid until Python is
+ finalized. The layout is the same for all Python sub-interpreters
+ in a process, and so it can be cached.
+
+
+.. c:struct:: PyLongExport
+
+ Export of a Python :class:`int` object.
+
+ There are two cases:
+
+ * If :c:member:`digits` is ``NULL``, only use the :c:member:`value` member.
+ * If :c:member:`digits` is not ``NULL``, use :c:member:`negative`,
+ :c:member:`ndigits` and :c:member:`digits` members.
+
+ .. c:member:: int64_t value
+
+ The native integer value of the exported :class:`int` object.
+ Only valid if :c:member:`digits` is ``NULL``.
+
+ .. c:member:: uint8_t negative
+
+ ``1`` if the number is negative, ``0`` otherwise.
+ Only valid if :c:member:`digits` is not ``NULL``.
+
+ .. c:member:: Py_ssize_t ndigits
+
+ Number of digits in :c:member:`digits` array.
+ Only valid if :c:member:`digits` is not ``NULL``.
+
+ .. c:member:: const void *digits
+
+ Read-only array of unsigned digits. Can be ``NULL``.
+
+
+.. c:function:: int PyLong_Export(PyObject *obj, PyLongExport *export_long)
+
+ Export a Python :class:`int` object.
+
+ *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``.
+
+ :c:func:`PyLong_FreeExport` must be called when the export is no longer
+ needed.
+
+ .. impl-detail::
+ This function always succeeds if *obj* is a Python :class:`int` object
+ or a subclass.
+
+
+.. c:function:: void PyLong_FreeExport(PyLongExport *export_long)
+
+ Release the export *export_long* created by :c:func:`PyLong_Export`.
+
+ .. impl-detail::
+ Calling :c:func:`PyLong_FreeExport` is optional if *export_long->digits*
+ is ``NULL``.
+
+
+PyLongWriter API
+^^^^^^^^^^^^^^^^
+
+The :c:type:`PyLongWriter` API can be used to import an integer.
+
+.. versionadded:: next
+
+.. c:struct:: PyLongWriter
+
+ A Python :class:`int` writer instance.
+
+ The instance must be destroyed by :c:func:`PyLongWriter_Finish` or
+ :c:func:`PyLongWriter_Discard`.
+
+
+.. c:function:: PyLongWriter* PyLongWriter_Create(int negative, Py_ssize_t ndigits, void **digits)
+
+ Create a :c:type:`PyLongWriter`.
+
+ On success, allocate *\*digits* and return a writer.
+ On error, set an exception and return ``NULL``.
+
+ *negative* is ``1`` if the number is negative, or ``0`` otherwise.
+
+ *ndigits* is the number of digits in the *digits* array. It must be
+ greater than 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.
+
+
+.. c:function:: PyObject* PyLongWriter_Finish(PyLongWriter *writer)
+
+ Finish a :c:type:`PyLongWriter` created by :c:func:`PyLongWriter_Create`.
+
+ On success, return a Python :class:`int` object.
+ On error, set an exception and return ``NULL``.
+
+ The function takes care of normalizing the digits and converts the object
+ to a compact integer if needed.
+
+ 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`.
+
+ *writer* must not be ``NULL``.
+
+ The writer instance and the *digits* array are invalid after the call.
diff --git a/Doc/data/refcounts.dat b/Doc/data/refcounts.dat
index a043af4..e78754e 100644
--- a/Doc/data/refcounts.dat
+++ b/Doc/data/refcounts.dat
@@ -1299,6 +1299,13 @@ PyLong_GetSign:int:::
PyLong_GetSign:PyObject*:v:0:
PyLong_GetSign:int*:sign::
+PyLong_Export:int:::
+PyLong_Export:PyObject*:obj:0:
+PyLong_Export:PyLongExport*:export_long::
+
+PyLongWriter_Finish:PyObject*::+1:
+PyLongWriter_Finish:PyLongWriter*:writer::
+
PyMapping_Check:int:::
PyMapping_Check:PyObject*:o:0:
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index b71d31f..5ce398a 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -1018,6 +1018,17 @@ New features
(Contributed by Victor Stinner in :gh:`107954`.)
+* Add a new import and export API for Python :class:`int` objects (:pep:`757`):
+
+ * :c:func:`PyLong_GetNativeLayout`;
+ * :c:func:`PyLong_Export`;
+ * :c:func:`PyLong_FreeExport`;
+ * :c:func:`PyLongWriter_Create`;
+ * :c:func:`PyLongWriter_Finish`;
+ * :c:func:`PyLongWriter_Discard`.
+
+ (Contributed by Victor Stinner in :gh:`102471`.)
+
* Add :c:func:`PyType_GetBaseByToken` and :c:data:`Py_tp_token` slot for easier
superclass identification, which attempts to resolve the `type checking issue
<https://peps.python.org/pep-0630/#type-checking>`__ mentioned in :pep:`630`