@@ -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