@@ -2336,15 +2336,16 @@ dec_from_long(decimal_state *state, PyTypeObject *type, PyObject *v,
23362336 }
23372337 if (export_long .digits ) {
23382338 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 ;
23422339
2343- assert (layout -> bits_per_digit <= 32 );
2340+ assert (layout -> bits_per_digit < 32 );
23442341 assert (layout -> digits_order == -1 );
23452342 assert (layout -> digit_endianness == (PY_LITTLE_ENDIAN ? -1 : 1 ));
23462343 assert (layout -> digit_size == 2 || layout -> digit_size == 4 );
23472344
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+
23482349 if (layout -> digit_size == 4 ) {
23492350 mpd_qimport_u32 (MPD (dec ), export_long .digits , len , sign ,
23502351 base , ctx , status );
@@ -3642,13 +3643,6 @@ dec_format(PyObject *dec, PyObject *args)
36423643static PyObject *
36433644dec_as_long (PyObject * dec , PyObject * context , int round )
36443645{
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-
36523646 if (mpd_isspecial (MPD (dec ))) {
36533647 if (mpd_isnan (MPD (dec ))) {
36543648 PyErr_SetString (PyExc_ValueError ,
@@ -3661,12 +3655,16 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
36613655 return NULL ;
36623656 }
36633657
3664- x = mpd_qnew ();
3658+ mpd_t * x = mpd_qnew ();
3659+
36653660 if (x == NULL ) {
36663661 PyErr_NoMemory ();
36673662 return NULL ;
36683663 }
3669- workctx = * CTX (context );
3664+
3665+ mpd_context_t workctx = * CTX (context );
3666+ uint32_t status = 0 ;
3667+
36703668 workctx .round = round ;
36713669 mpd_qround_to_int (x , MPD (dec ), & workctx , & status );
36723670 if (dec_addstatus (context , status )) {
@@ -3675,34 +3673,56 @@ dec_as_long(PyObject *dec, PyObject *context, int round)
36753673 }
36763674
36773675 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+ }
36863707
36873708 if (n == SIZE_MAX ) {
36883709 PyErr_NoMemory ();
36893710 mpd_del (x );
3711+ mpd_free (tmp_digits );
36903712 return NULL ;
36913713 }
36923714
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 );
36993717
3700- assert (n > 0 );
3701- assert (!mpd_iszero (x ));
3702- pylong = _PyLong_FromDigits (mpd_isnegative (x ), n , ob_digit );
3703- mpd_free (ob_digit );
37043718 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 );
37063726}
37073727
37083728/* Convert a Decimal to its exact integer ratio representation. */
0 commit comments