-
Notifications
You must be signed in to change notification settings - Fork 1
Description
That will allow fast import of CPython integers if external multiple precision library support mpz_import()
-like interface (e.g. LibTomMath has mp_unpack()
). Currently gmpy2 (see this or Sage (see this) use private API to do this. Using new PyLong_FromNativeBytes()
/ PyLong_AsNativeBytes()
will be a performance regression for such projects.
Proposed interface:
/* Access the integer value as an array of digits.
On success, return array of digits and set *ndigits to number of digits.
On failure, return NULL with an exception set.
This function always succeeds if obj is a PyLongObject or its subtype.
*/
const digits* PyLong_GetDigits(PyObject* obj, Py_ssize_t *ndigits);
API usage:
static void
mpz_set_PyLong(mpz_t z, PyObject *obj)
{
Py_ssize_t len;
const digit *digits = PyLong_GetDigits(obj, &len);
switch (len) {
case 1:
mpz_set_si(z, (sdigit)digits[0]);
break;
case 0:
mpz_set_si(z, 0);
break;
default:
mpz_import(z, len, -1, sizeof(digit), 0,
sizeof(digit)*8 - PYLONG_BITS_IN_DIGIT, digits);
}
int sign = 1;
PyLong_GetSign(obj, &sign);
if (sign < 0) {
mpz_neg(z, z);
}
return;
}
Above interface resembles combined GMP's functions mpz_size()
and mpz_limbs_read()
. It might worth to consider also export from external multiple precision libraries, that offer mpz_export()
-like API. gmpy2 does this using private API to access digits/digit count and also the _PyLong_New()
to allocate an integer of appropriate size.
So, alternative interface to support both reading and writing might look like this:
/* Return number of digits or -1 on failure. Shouldn't fail on int's. */
Py_ssize_t PyLong_DigitCount(PyObject *obj);
/* Return array of digits or NULL on failure. Shouldn't fail on int's. */
digit* PyLong_GetDigits(PyObject *obj);
/* Return a new integer object with unspecified absolute value of given
size (in digits) and with a given sign. On failure return NULL */
PyObject* PyLong_New(const Py_ssize_t ndigits, const int sign);
The PyLong_New()
shouldn't violate #56: freshly created integer will be a correct one, just with an unspecified absolute value.