Skip to content

Commit

Permalink
PEP 757: misc edits (#3984)
Browse files Browse the repository at this point in the history
  • Loading branch information
skirpichev authored Sep 20, 2024
1 parent c5010ea commit ab9258d
Showing 1 changed file with 33 additions and 26 deletions.
59 changes: 33 additions & 26 deletions peps/pep-0757.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ Export API
Read-only array of unsigned digits. Can be ``NULL``.
If :c:member:`digits` not ``NULL``, a private field of the
:c:struct:`PyLongExport` structure stores a strong reference to the Python
:class:`int` object to make sure that that structure remains valid until
:c:func:`PyLong_FreeExport()` is called.
.. c:function:: int PyLong_Export(PyObject *obj, PyLongExport *export_long)
Expand All @@ -146,11 +151,6 @@ Export API
On CPython 3.14, no memory copy is needed, it's just a thin wrapper to
expose Python int internal digits array.
If :c:member:`~PyLongExport.digits` not ``NULL``, a private field of
the :c:struct:`PyLongExport` structure stores a strong reference to
the Python :class:`int` object to make sure that that structure
remains valid until :c:func:`PyLong_FreeExport()` is called.
.. c:function:: void PyLong_FreeExport(PyLongExport *export_long)
Expand Down Expand Up @@ -183,9 +183,9 @@ create a Python :class:`int` object from a digits array.
greater than or equal to 0.
The caller must initialize the array of digits *digits* and then call
:c:func:`PyLongWriter_Finish` to get a Python :class:`int`. Digits must be
in the range [``0``; ``PyLong_BASE - 1``]. Unused digits must be set to
``0``.
:c:func:`PyLongWriter_Finish` to get a Python :class:`int`. Digits must be
in the range [``0``; ``(1 << sys.int_info.bits_per_digit) - 1``]. Unused digits must
be set to ``0``.
On CPython 3.14, the implementation is a thin wrapper to the private
:c:func:`!_PyLong_New()` function.
Expand Down Expand Up @@ -238,6 +238,18 @@ Implementation
Benchmarks
==========
Code::
/* Query parameters of Python’s internal representation of integers. */
const PyLongLayout *layout = PyLong_GetNativeLayout();
size_t int_digit_size = layout->digit_size;
int int_digits_order = layout->digits_order;
size_t int_bits_per_digit = layout->bits_per_digit;
size_t int_nails = int_digit_size*8 - int_bits_per_digit;
int int_endianness = layout->endianness;
Export: :c:func:`PyLong_Export()` with gmpy2
--------------------------------------------
Expand All @@ -246,28 +258,26 @@ Code::
static void
mpz_set_PyLong(mpz_t z, PyObject *obj)
{
const PyLongLayout* layout = PyLong_GetNativeLayout();
static PyLongExport long_export;
PyLong_Export(obj, &long_export);
if (long_export.digits) {
mpz_import(z, long_export.ndigits, layout->digits_order,
layout->digit_size, layout->endianness,
layout->digit_size*8 - layout->bits_per_digit,
long_export.digits);
mpz_import(z, long_export.ndigits, int_digits_order, int_digit_size,
int_endianness, int_nails, long_export.digits);
if (long_export.negative) {
mpz_neg(z, z);
}
PyLong_FreeExport(&long_export);
}
else {
if (LONG_MIN <= long_export.value && long_export.value <= LONG_MAX) {
mpz_set_si(z, long_export.value);
const int64_t value = long_export.value;
if (LONG_MIN <= value && value <= LONG_MAX) {
mpz_set_si(z, value);
}
else {
mpz_import(z, 1, -1, sizeof(int64_t), 0, 0,
&long_export.value);
if (long_export.value < 0) {
mpz_import(z, 1, -1, sizeof(int64_t), 0, 0, &value);
if (value < 0) {
mpz_t tmp;
mpz_init(tmp);
mpz_ui_pow_ui(tmp, 2, 64);
Expand Down Expand Up @@ -324,20 +334,17 @@ Code::
return PyLong_FromLong(mpz_get_si(obj->z));
}
const PyLongLayout *layout = PyLong_GetNativeLayout();
size_t size = (mpz_sizeinbase(obj->z, 2) +
layout->bits_per_digit - 1) / layout->bits_per_digit;
int_bits_per_digit - 1) / int_bits_per_digit;
void *digits;
PyLongWriter *writer = PyLongWriter_Create(mpz_sgn(obj->z) < 0, size,
&digits);
if (writer == NULL) {
return NULL;
}
mpz_export(digits, NULL, layout->endianness,
layout->digit_size, layout->digits_order,
layout->digit_size*8 - layout->bits_per_digit,
obj->z);
mpz_export(digits, NULL, int_digits_order, int_digit_size,
int_endianness, int_nails, obj->z);
return PyLongWriter_Finish(writer);
}
Expand Down Expand Up @@ -389,11 +396,11 @@ Open Questions
:c:func:`PyLong_GetNativeLayout()` function returns a C structure
which is more convenient to use in C than :data:`sys.int_info` which uses
Python objects.
* Currenly, all required information for :class:`int` import/export is
* Currently, all required information for :class:`int` import/export is
already available via :c:func:`PyLong_GetInfo()` or :data:`sys.int_info`.
Native endianness of "digits" and current order of digits (least
significant digit first) --- is a common denominator of all libraries
for aribitrary precision integer arithmetic. So, shouldn't we just remove
for arbitrary precision integer arithmetic. So, shouldn't we just remove
from API both :c:struct:`PyLongLayout` and :c:func:`PyLong_GetNativeLayout()` (which
is actually just a minor convenience)?
Expand Down

0 comments on commit ab9258d

Please sign in to comment.