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