@@ -388,37 +388,86 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp
388388 return MP_OBJ_NULL ; // op not supported
389389}
390390
391- // this is a classmethod
392- static mp_obj_t int_from_bytes (size_t n_args , const mp_obj_t * args ) {
393- // TODO: Support signed param (assumes signed=False at the moment)
394-
395- // get the buffer info
396- mp_buffer_info_t bufinfo ;
397- mp_get_buffer_raise (args [1 ], & bufinfo , MP_BUFFER_READ );
391+ void * reverce_memcpy (void * dest , const void * src , size_t len ) {
392+ char * d = (char * )dest + len - 1 ;
393+ const char * s = src ;
394+ while (len -- ) {
395+ * d -- = * s ++ ;
396+ }
397+ return dest ;
398+ }
398399
399- const byte * buf = (const byte * )bufinfo .buf ;
400- int delta = 1 ;
401- bool big_endian = n_args < 3 || args [2 ] != MP_OBJ_NEW_QSTR (MP_QSTR_little );
402- if (!big_endian ) {
403- buf += bufinfo .len - 1 ;
404- delta = -1 ;
400+ mp_obj_t mp_obj_integer_from_bytes_impl (bool big_endian , bool is_signed , size_t len , const byte * buf ) {
401+ if (len > sizeof (mp_int_t )) {
402+ #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
403+ // Result will overflow a small-int size so construct a big-int
404+ return mp_obj_int_from_bytes_impl (big_endian , is_signed , len , buf );
405+ #else
406+ mp_raise_msg (& mp_type_OverflowError , MP_ERROR_TEXT ("small-int overflow" ));
407+ #endif
408+ }
409+ union {
410+ mp_int_t value ;
411+ mp_uint_t uvalue ;
412+ byte buf [sizeof (mp_int_t )];
413+ } result = {0 };
414+ // #if sizeof(mp_int_t) != sizeof(mp_uint_t)
415+ // #error "sizeof(mp_int_t) != sizeof(mp_uint_t)"
416+ // #endif
417+
418+ if (big_endian ) {
419+ reverce_memcpy (& result , buf , len );
420+ } else { // little-endian
421+ memcpy (& result , buf , len );
405422 }
406423
407- mp_uint_t value = 0 ;
408- size_t len = bufinfo .len ;
409- for (; len -- ; buf += delta ) {
424+ if ((is_signed ) && (sizeof (result ) > len ) && (result .buf [len - 1 ] & 0x80 )) {
425+ // Sign propagation in little-endian
426+ // x = 2
427+ // x.to_bytes(1, 'little', True) -> b'\x02'
428+ // x.to_bytes(4, 'little', True) -> b'\x02\x00\x00\x00'
429+ // x = -2
430+ // x.to_bytes(1, 'little', True) -> b'\xFE'
431+ // x.to_bytes(4, 'little', True) -> b'\xFE\xFF\xFF\xFF'
432+ memset (result .buf + len , 0xFF , sizeof (result ) - len );
433+ }
434+ if (((!is_signed ) && (result .uvalue > MP_SMALL_INT_MAX )) || (is_signed && ((result .value < MP_SMALL_INT_MIN ) || (result .value > MP_SMALL_INT_MAX )))) {
435+ // Result will overflow a small-int so construct a big-int
410436 #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
411- if (value > (MP_SMALL_INT_MAX >> 8 )) {
412- // Result will overflow a small-int so construct a big-int
413- return mp_obj_int_from_bytes_impl (big_endian , bufinfo .len , bufinfo .buf );
414- }
437+ return mp_obj_int_from_bytes_impl (big_endian , is_signed , len , buf );
438+ #else
439+ mp_raise_msg (& mp_type_OverflowError , MP_ERROR_TEXT ("small-int overflow" ));
415440 #endif
416- value = (value << 8 ) | * buf ;
417441 }
418- return mp_obj_new_int_from_uint ( value );
442+ return mp_obj_new_int ( result . value );
419443}
420444
421- static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (int_from_bytes_fun_obj , 2 , 4 , int_from_bytes ) ;
445+ // this is a classmethod
446+ // result = int.from_bytes(bytearray(), [[length=,] byteorder='big',] signed=False)
447+ static mp_obj_t int_from_bytes (size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
448+ enum { ARG_length , ARG_byteorder , ARG_signed };
449+ static const mp_arg_t allowed_args [] = {
450+ { MP_QSTR_length , MP_ARG_INT , { .u_int = 0 } },
451+ { MP_QSTR_byteorder , MP_ARG_OBJ , { .u_rom_obj = MP_ROM_QSTR (MP_QSTR_big ) } },
452+ { MP_QSTR_signed , MP_ARG_BOOL , {.u_bool = false} },
453+ };
454+ mp_arg_val_t args [MP_ARRAY_SIZE (allowed_args )];
455+ mp_arg_parse_all (n_args - 2 , pos_args + 2 , kw_args , MP_ARRAY_SIZE (allowed_args ), allowed_args , args );
456+
457+ // get the buffer info
458+ mp_buffer_info_t bufinfo ;
459+ mp_get_buffer_raise (pos_args [1 ], & bufinfo , MP_BUFFER_READ );
460+
461+ size_t len = args [ARG_length ].u_int ;
462+ bool big_endian = args [ARG_byteorder ].u_obj != MP_OBJ_NEW_QSTR (MP_QSTR_little );
463+ bool is_signed = args [ARG_signed ].u_bool ;
464+
465+ if ((len <= 0 ) || (len > bufinfo .len )) {
466+ len = bufinfo .len ;
467+ }
468+ return mp_obj_integer_from_bytes_impl (big_endian , is_signed , len , bufinfo .buf );
469+ }
470+ static MP_DEFINE_CONST_FUN_OBJ_KW (int_from_bytes_fun_obj , 2 , int_from_bytes ) ;
422471static MP_DEFINE_CONST_CLASSMETHOD_OBJ (int_from_bytes_obj , MP_ROM_PTR (& int_from_bytes_fun_obj )) ;
423472
424473static mp_obj_t int_to_bytes (size_t n_args , const mp_obj_t * args ) {
0 commit comments