mirror of https://github.com/python/cpython.git
gh-127937: Convert decimal to use PEP 757 import API (#127925)
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
parent
6e63c4736b
commit
3d8fc8b9ae
|
@ -0,0 +1,3 @@
|
|||
Convert the :mod:`decimal` module to use :pep:`757` C API (export-import
|
||||
integers), offering some speed-up if the integer part of the
|
||||
:class:`~decimal.Decimal` instance is small. Patch by Sergey B Kirpichev.
|
|
@ -2336,15 +2336,16 @@ dec_from_long(decimal_state *state, PyTypeObject *type, PyObject *v,
|
|||
}
|
||||
if (export_long.digits) {
|
||||
const PyLongLayout *layout = PyLong_GetNativeLayout();
|
||||
uint32_t base = (uint32_t)1 << layout->bits_per_digit;
|
||||
uint8_t sign = export_long.negative ? MPD_NEG : MPD_POS;
|
||||
Py_ssize_t len = export_long.ndigits;
|
||||
|
||||
assert(layout->bits_per_digit <= 32);
|
||||
assert(layout->bits_per_digit < 32);
|
||||
assert(layout->digits_order == -1);
|
||||
assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1));
|
||||
assert(layout->digit_size == 2 || layout->digit_size == 4);
|
||||
|
||||
uint32_t base = (uint32_t)1 << layout->bits_per_digit;
|
||||
uint8_t sign = export_long.negative ? MPD_NEG : MPD_POS;
|
||||
Py_ssize_t len = export_long.ndigits;
|
||||
|
||||
if (layout->digit_size == 4) {
|
||||
mpd_qimport_u32(MPD(dec), export_long.digits, len, sign,
|
||||
base, ctx, status);
|
||||
|
@ -3642,13 +3643,6 @@ dec_format(PyObject *dec, PyObject *args)
|
|||
static PyObject *
|
||||
dec_as_long(PyObject *dec, PyObject *context, int round)
|
||||
{
|
||||
PyLongObject *pylong;
|
||||
digit *ob_digit;
|
||||
size_t n;
|
||||
mpd_t *x;
|
||||
mpd_context_t workctx;
|
||||
uint32_t status = 0;
|
||||
|
||||
if (mpd_isspecial(MPD(dec))) {
|
||||
if (mpd_isnan(MPD(dec))) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
|
@ -3661,12 +3655,16 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
x = mpd_qnew();
|
||||
mpd_t *x = mpd_qnew();
|
||||
|
||||
if (x == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
workctx = *CTX(context);
|
||||
|
||||
mpd_context_t workctx = *CTX(context);
|
||||
uint32_t status = 0;
|
||||
|
||||
workctx.round = round;
|
||||
mpd_qround_to_int(x, MPD(dec), &workctx, &status);
|
||||
if (dec_addstatus(context, status)) {
|
||||
|
@ -3675,34 +3673,56 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
|
|||
}
|
||||
|
||||
status = 0;
|
||||
ob_digit = NULL;
|
||||
#if PYLONG_BITS_IN_DIGIT == 30
|
||||
n = mpd_qexport_u32(&ob_digit, 0, PyLong_BASE, x, &status);
|
||||
#elif PYLONG_BITS_IN_DIGIT == 15
|
||||
n = mpd_qexport_u16(&ob_digit, 0, PyLong_BASE, x, &status);
|
||||
#else
|
||||
#error "PYLONG_BITS_IN_DIGIT should be 15 or 30"
|
||||
#endif
|
||||
int64_t val = mpd_qget_i64(x, &status);
|
||||
|
||||
if (!status) {
|
||||
mpd_del(x);
|
||||
return PyLong_FromInt64(val);
|
||||
}
|
||||
assert(!mpd_iszero(x));
|
||||
|
||||
const PyLongLayout *layout = PyLong_GetNativeLayout();
|
||||
|
||||
assert(layout->bits_per_digit < 32);
|
||||
assert(layout->digits_order == -1);
|
||||
assert(layout->digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1));
|
||||
assert(layout->digit_size == 2 || layout->digit_size == 4);
|
||||
|
||||
uint32_t base = (uint32_t)1 << layout->bits_per_digit;
|
||||
/* We use a temporary buffer for digits for now, as for nonzero rdata
|
||||
mpd_qexport_u32/u16() require either space "allocated by one of
|
||||
libmpdec’s allocation functions" or "rlen MUST be correct" (to avoid
|
||||
reallocation). This can be further optimized by using rlen from
|
||||
mpd_sizeinbase(). See gh-127925. */
|
||||
void *tmp_digits = NULL;
|
||||
size_t n;
|
||||
|
||||
status = 0;
|
||||
if (layout->digit_size == 4) {
|
||||
n = mpd_qexport_u32((uint32_t **)&tmp_digits, 0, base, x, &status);
|
||||
}
|
||||
else {
|
||||
n = mpd_qexport_u16((uint16_t **)&tmp_digits, 0, base, x, &status);
|
||||
}
|
||||
|
||||
if (n == SIZE_MAX) {
|
||||
PyErr_NoMemory();
|
||||
mpd_del(x);
|
||||
mpd_free(tmp_digits);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (n == 1) {
|
||||
sdigit val = mpd_arith_sign(x) * ob_digit[0];
|
||||
mpd_free(ob_digit);
|
||||
mpd_del(x);
|
||||
return PyLong_FromLong(val);
|
||||
}
|
||||
void *digits;
|
||||
PyLongWriter *writer = PyLongWriter_Create(mpd_isnegative(x), n, &digits);
|
||||
|
||||
assert(n > 0);
|
||||
assert(!mpd_iszero(x));
|
||||
pylong = _PyLong_FromDigits(mpd_isnegative(x), n, ob_digit);
|
||||
mpd_free(ob_digit);
|
||||
mpd_del(x);
|
||||
return (PyObject *) pylong;
|
||||
if (writer == NULL) {
|
||||
mpd_free(tmp_digits);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(digits, tmp_digits, layout->digit_size*n);
|
||||
mpd_free(tmp_digits);
|
||||
return PyLongWriter_Finish(writer);
|
||||
}
|
||||
|
||||
/* Convert a Decimal to its exact integer ratio representation. */
|
||||
|
|
Loading…
Reference in New Issue