diff --git a/gmp.c b/gmp.c index 9485fd03..2972ddc4 100644 --- a/gmp.c +++ b/gmp.c @@ -180,49 +180,12 @@ MPZ_from_str(PyObject *obj, int base) return res; } +static zz_err zz_set_bytes(const unsigned char *buffer, size_t length, + bool is_signed, zz_t *u); + static MPZ_Object * MPZ_from_int(PyObject *obj) { -#if defined(ON_CPYTHON) && !defined(Py_LIMITED_API) - PyLongExport long_export = {0, 0, 0, 0, 0}; - const zz_layout *int_layout = (zz_layout *)PyLong_GetNativeLayout(); - MPZ_Object *res = NULL; - - if (PyLong_Export(obj, &long_export) < 0) { - return res; /* LCOV_EXCL_LINE */ - } - if (long_export.digits) { - res = MPZ_new(); - if (!res) { - return NULL; /* LCOV_EXCL_LINE */ - } - - zz_err ret = zz_import((size_t)long_export.ndigits, - long_export.digits, *int_layout, &res->z); - - if (ret) { - /* LCOV_EXCL_START */ - if (ret == ZZ_MEM) { - return (MPZ_Object *)PyErr_NoMemory(); - } - PyErr_SetString(PyExc_OverflowError, - "too many digits in integer"); - return NULL; - /* LCOV_EXCL_STOP */ - } - if (long_export.negative) { - (void)zz_neg(&res->z, &res->z); - } - PyLong_FreeExport(&long_export); - } - else { - res = MPZ_new(); - if (res && zz_set(long_export.value, &res->z)) { - PyErr_NoMemory(); /* LCOV_EXCL_LINE */ - } - } - return res; -#else int64_t value; if (!PyLong_AsInt64(obj, &value)) { @@ -235,6 +198,50 @@ MPZ_from_int(PyObject *obj) } PyErr_Clear(); +#if defined(ON_CPYTHON) && PY_VERSION_HEX > 0x030D00A0 \ + && !defined(Py_LIMITED_API) + Py_ssize_t expected = PyLong_AsNativeBytes(obj, NULL, 0, 0); + + if (expected < 0) { + return NULL; /* LCOV_EXCL_LINE */ + } + + unsigned char *buffer = malloc((size_t)expected); + + if (!buffer) { + return (MPZ_Object *)PyErr_NoMemory(); /* LCOV_EXCL_LINE */ + } + + expected = PyLong_AsNativeBytes(obj, buffer, expected, 0); + if (expected < 0) { +free: + /* LCOV_EXCL_START */ + free(buffer); + return NULL; + /* LCOV_EXCL_STOP */ + } + + MPZ_Object *res = MPZ_new(); + + if (!res) { + goto free; /* LCOV_EXCL_LINE */ + } + + zz_err ret = zz_set_bytes(buffer, (size_t)expected, true, &res->z); + + free(buffer); + if (ret) { + /* LCOV_EXCL_START */ + if (ret == ZZ_MEM) { + return (MPZ_Object *)PyErr_NoMemory(); + } + PyErr_SetString(PyExc_OverflowError, + "too many digits in integer"); + return NULL; + /* LCOV_EXCL_STOP */ + } + return res; +#else PyObject *str = PyNumber_ToBase(obj, 16); if (!str) { @@ -245,9 +252,14 @@ MPZ_from_int(PyObject *obj) Py_DECREF(str); return res; -#endif /* defined(ON_CPYTHON) && !defined(Py_LIMITED_API) */ +#endif /* defined(ON_CPYTHON) && PY_VERSION_HEX > 0x030D00A0 + && !defined(Py_LIMITED_API) */ } +static zz_err zz_get_bytes(const zz_t *u, size_t length, + bool is_signed, unsigned char **buffer); +static void revstr(unsigned char *s, Py_ssize_t l, Py_ssize_t r); + static PyObject * MPZ_to_int(MPZ_Object *u) { @@ -257,19 +269,21 @@ MPZ_to_int(MPZ_Object *u) return PyLong_FromInt64(value); } -#if defined(ON_CPYTHON) && !defined(Py_LIMITED_API) - const zz_layout *int_layout = (zz_layout *)PyLong_GetNativeLayout(); - size_t size = (zz_bitlen(&u->z) + int_layout->bits_per_digit - - 1)/int_layout->bits_per_digit; - void *digits; - PyLongWriter *writer = PyLongWriter_Create(zz_isneg(&u->z), - (Py_ssize_t)size, &digits); +#if defined(ON_CPYTHON) && PY_VERSION_HEX > 0x030D00A0 \ + && !defined(Py_LIMITED_API) + size_t size = (zz_bitlen(&u->z) + 7)/8 + 1; + unsigned char *buffer = malloc(size); - if (!writer) { - return NULL; /* LCOV_EXCL_LINE */ + if (!buffer) { + return PyErr_NoMemory(); /* LCOV_EXCL_LINE */ } - (void)zz_export(&u->z, *int_layout, size, digits); - return PyLongWriter_Finish(writer); + (void)zz_get_bytes(&u->z, size, true, &buffer); + revstr(buffer, 0, (Py_ssize_t)size - 1); + + PyObject *res = PyLong_FromNativeBytes(buffer, size, -1); + + free(buffer); + return res; #else size_t len; @@ -289,7 +303,8 @@ MPZ_to_int(MPZ_Object *u) free(buf); return res; -#endif /* defined(ON_CPYTHON) && !defined(Py_LIMITED_API) */ +#endif /* defined(ON_CPYTHON) && PY_VERSION_HEX > 0x030D00A0 + && !defined(Py_LIMITED_API) */ } static void