@@ -2336,15 +2336,16 @@ dec_from_long(decimal_state *state, PyTypeObject *type, PyObject *v,
2336
2336
}
2337
2337
if (export_long .digits ) {
2338
2338
const PyLongLayout * layout = PyLong_GetNativeLayout ();
2339
- uint32_t base = (uint32_t )1 << layout -> bits_per_digit ;
2340
- uint8_t sign = export_long .negative ? MPD_NEG : MPD_POS ;
2341
- Py_ssize_t len = export_long .ndigits ;
2342
2339
2343
- assert (layout -> bits_per_digit <= 32 );
2340
+ assert (layout -> bits_per_digit < 32 );
2344
2341
assert (layout -> digits_order == -1 );
2345
2342
assert (layout -> digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1 ));
2346
2343
assert (layout -> digit_size == 2 || layout -> digit_size == 4 );
2347
2344
2345
+ uint32_t base = (uint32_t )1 << layout -> bits_per_digit ;
2346
+ uint8_t sign = export_long .negative ? MPD_NEG : MPD_POS ;
2347
+ Py_ssize_t len = export_long .ndigits ;
2348
+
2348
2349
if (layout -> digit_size == 4 ) {
2349
2350
mpd_qimport_u32 (MPD (dec ), export_long .digits , len , sign ,
2350
2351
base , ctx , status );
@@ -3642,13 +3643,6 @@ dec_format(PyObject *dec, PyObject *args)
3642
3643
static PyObject *
3643
3644
dec_as_long (PyObject * dec , PyObject * context , int round )
3644
3645
{
3645
- PyLongObject * pylong ;
3646
- digit * ob_digit ;
3647
- size_t n ;
3648
- mpd_t * x ;
3649
- mpd_context_t workctx ;
3650
- uint32_t status = 0 ;
3651
-
3652
3646
if (mpd_isspecial (MPD (dec ))) {
3653
3647
if (mpd_isnan (MPD (dec ))) {
3654
3648
PyErr_SetString (PyExc_ValueError ,
@@ -3661,12 +3655,16 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
3661
3655
return NULL ;
3662
3656
}
3663
3657
3664
- x = mpd_qnew ();
3658
+ mpd_t * x = mpd_qnew ();
3659
+
3665
3660
if (x == NULL ) {
3666
3661
PyErr_NoMemory ();
3667
3662
return NULL ;
3668
3663
}
3669
- workctx = * CTX (context );
3664
+
3665
+ mpd_context_t workctx = * CTX (context );
3666
+ uint32_t status = 0 ;
3667
+
3670
3668
workctx .round = round ;
3671
3669
mpd_qround_to_int (x , MPD (dec ), & workctx , & status );
3672
3670
if (dec_addstatus (context , status )) {
@@ -3675,34 +3673,56 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
3675
3673
}
3676
3674
3677
3675
status = 0 ;
3678
- ob_digit = NULL ;
3679
- #if PYLONG_BITS_IN_DIGIT == 30
3680
- n = mpd_qexport_u32 (& ob_digit , 0 , PyLong_BASE , x , & status );
3681
- #elif PYLONG_BITS_IN_DIGIT == 15
3682
- n = mpd_qexport_u16 (& ob_digit , 0 , PyLong_BASE , x , & status );
3683
- #else
3684
- #error "PYLONG_BITS_IN_DIGIT should be 15 or 30"
3685
- #endif
3676
+ int64_t val = mpd_qget_i64 (x , & status );
3677
+
3678
+ if (!status ) {
3679
+ mpd_del (x );
3680
+ return PyLong_FromInt64 (val );
3681
+ }
3682
+ assert (!mpd_iszero (x ));
3683
+
3684
+ const PyLongLayout * layout = PyLong_GetNativeLayout ();
3685
+
3686
+ assert (layout -> bits_per_digit < 32 );
3687
+ assert (layout -> digits_order == -1 );
3688
+ assert (layout -> digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1 ));
3689
+ assert (layout -> digit_size == 2 || layout -> digit_size == 4 );
3690
+
3691
+ uint32_t base = (uint32_t )1 << layout -> bits_per_digit ;
3692
+ /* We use a temporary buffer for digits for now, as for nonzero rdata
3693
+ mpd_qexport_u32/u16() require either space "allocated by one of
3694
+ libmpdec’s allocation functions" or "rlen MUST be correct" (to avoid
3695
+ reallocation). This can be further optimized by using rlen from
3696
+ mpd_sizeinbase(). See gh-127925. */
3697
+ void * tmp_digits = NULL ;
3698
+ size_t n ;
3699
+
3700
+ status = 0 ;
3701
+ if (layout -> digit_size == 4 ) {
3702
+ n = mpd_qexport_u32 ((uint32_t * * )& tmp_digits , 0 , base , x , & status );
3703
+ }
3704
+ else {
3705
+ n = mpd_qexport_u16 ((uint16_t * * )& tmp_digits , 0 , base , x , & status );
3706
+ }
3686
3707
3687
3708
if (n == SIZE_MAX ) {
3688
3709
PyErr_NoMemory ();
3689
3710
mpd_del (x );
3711
+ mpd_free (tmp_digits );
3690
3712
return NULL ;
3691
3713
}
3692
3714
3693
- if (n == 1 ) {
3694
- sdigit val = mpd_arith_sign (x ) * ob_digit [0 ];
3695
- mpd_free (ob_digit );
3696
- mpd_del (x );
3697
- return PyLong_FromLong (val );
3698
- }
3715
+ void * digits ;
3716
+ PyLongWriter * writer = PyLongWriter_Create (mpd_isnegative (x ), n , & digits );
3699
3717
3700
- assert (n > 0 );
3701
- assert (!mpd_iszero (x ));
3702
- pylong = _PyLong_FromDigits (mpd_isnegative (x ), n , ob_digit );
3703
- mpd_free (ob_digit );
3704
3718
mpd_del (x );
3705
- return (PyObject * ) pylong ;
3719
+ if (writer == NULL ) {
3720
+ mpd_free (tmp_digits );
3721
+ return NULL ;
3722
+ }
3723
+ memcpy (digits , tmp_digits , layout -> digit_size * n );
3724
+ mpd_free (tmp_digits );
3725
+ return PyLongWriter_Finish (writer );
3706
3726
}
3707
3727
3708
3728
/* Convert a Decimal to its exact integer ratio representation. */
0 commit comments