diff --git a/ports/esp32/mpconfigport.h b/ports/esp32/mpconfigport.h index b5b7d63a56333..e6e469fd4902c 100644 --- a/ports/esp32/mpconfigport.h +++ b/ports/esp32/mpconfigport.h @@ -61,8 +61,8 @@ #define MICROPY_ENABLE_GC (1) #define MICROPY_STACK_CHECK_MARGIN (1024) #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1) -#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) -#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) // (MICROPY_LONGINT_IMPL_MPZ) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL + 1) #define MICROPY_WARNINGS (1) #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #define MICROPY_STREAMS_POSIX_API (1) diff --git a/py/objint.c b/py/objint.c index 4be6009a440e4..0bd98cef00402 100644 --- a/py/objint.c +++ b/py/objint.c @@ -39,6 +39,9 @@ #include #endif +#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, "\n"); // mp_printf(&mp_plat_print, " | func:%s line:%d at %s\n", __FUNCTION__, __LINE__, __FILE__); +#define _debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__); + // This dispatcher function is expected to be independent of the implementation of long int static mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { (void)type_in; @@ -387,6 +390,7 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp return MP_OBJ_NULL; // op not supported } +/* // this is a classmethod static mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) { // TODO: Support signed param (assumes signed=False at the moment) @@ -416,6 +420,102 @@ static mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) { } return mp_obj_new_int_from_uint(value); } +*/ +/* +int calc_size(mp_longint_impl_t x) { + int size = 0; + if (x < 0) { + x = -x; + } + do { + x >>= 8; + size++; + } while (x); + return size; +} +*/ +void *reverce_memcpy(void *dest, const void *src, size_t len) { + char *d = (char *)dest + len - 1; + const char *s = src; + while (len--) { + *d-- = *s++; + } + return dest; +} + +// this is a classmethod +// result = int.int_from_bytes(bytearray(), order='big', signed=False) +static mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + bool big_endian = (n_args < 3) || (args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little)); + bool signd = (n_args > 3) && mp_obj_is_true(args[3]); + + // debug_printf("mp_obj_is_bool(args[3])=%d", mp_obj_is_bool(args[3])); + // debug_printf("n_args=%d, MP_SMALL_INT_MAX=%d, MP_SMALL_INT_MIN=%d", n_args, MP_SMALL_INT_MAX, MP_SMALL_INT_MIN); + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + if ((1ULL << (bufinfo.len * 8 - 2)) > (MP_SMALL_INT_MAX + 1)) { + debug_printf("//1 Result will overflow a small-int so construct a big-int"); + debug_printf("big_endian:%d signed:%d bufinfo.len:%d", big_endian, signd, bufinfo.len); + return mp_obj_int_from_bytes_impl(big_endian, signd, bufinfo.len, bufinfo.buf); + } + #endif + + union { + mp_int_t ival; + mp_uint_t uval; + byte buf[sizeof(mp_uint_t)]; + } result = {0}; + + if (bufinfo.len > sizeof(result)) { + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small-int too large")); + bufinfo.len = sizeof(result); + } + + if (big_endian) { + reverce_memcpy(&result.uval, bufinfo.buf, bufinfo.len); + } else { // little endian + memcpy(&result.uval, bufinfo.buf, bufinfo.len); + } + if (signd) { + if ((sizeof(result) > bufinfo.len) && (result.buf[bufinfo.len - 1] & 0x80)) { + // Sign propagation + // x = 2 + // x.to_bytes(1, 'little', True) -> b'\x02' + // x.to_bytes(4, 'little', True) -> b'\x02\x00\x00\x00' + // x = -2 + // x.to_bytes(1, 'little', True) -> b'\xFE' + // x.to_bytes(4, 'little', True) -> b'\xFE\xFF\xFF\xFF' + debug_printf("result=0x%08X", result.uval); + for (unsigned int i = 0; i < sizeof(result); i++) { + _debug_printf("\\%02X", result.buf[i]); + } + memset(result.buf + bufinfo.len, 0xFF, sizeof(result) - bufinfo.len); + debug_printf("\nresult=0x%08X", result.uval); + for (unsigned int i = 0; i < sizeof(result); i++) { + _debug_printf("\\%02X", result.buf[i]); + } + debug_printf(""); + } + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + // debug_printf("big_endian:%d signed:%d bufinfo.len:%d sizeof(result.ival):%d result.ival:%ld", big_endian, signd, bufinfo.len, sizeof(result.ival), result.ival); + if (!MP_SMALL_INT_FITS(result.ival)) { + debug_printf("//2 Result will overflow a small-int so construct a big-int"); + return mp_obj_int_from_bytes_impl(big_endian, signd, bufinfo.len, bufinfo.buf); + } + #endif + return mp_obj_new_int(result.ival); + } else { + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + // debug_printf("big_endian:%d signed:%d bufinfo.len:%d sizeof(result.uval):%d result.uval:%ld", big_endian, signd, bufinfo.len, sizeof(result.uval), result.uval); + if (!MP_SMALL_UINT_FITS(result.uval)) { + debug_printf("//3 Result will overflow a small-int so construct a big-int"); + return mp_obj_int_from_bytes_impl(big_endian, signd, bufinfo.len, bufinfo.buf); + } + #endif + return mp_obj_new_int_from_uint(result.uval); + } +} static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 2, 4, int_from_bytes); static MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, MP_ROM_PTR(&int_from_bytes_fun_obj)); diff --git a/py/objint.h b/py/objint.h index 28930e35adb49..d51ce1cc7afc8 100644 --- a/py/objint.h +++ b/py/objint.h @@ -54,7 +54,7 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in, int base, const char *prefix, char base_char, char comma); mp_int_t mp_obj_int_hash(mp_obj_t self_in); -mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf); +mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, bool signd, size_t len, const byte *buf); // Returns true if 'self_in' fit into 'len' bytes of 'buf' without overflowing, 'buf' is truncated otherwise. bool mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf); int mp_obj_int_sign(mp_obj_t self_in); @@ -62,5 +62,7 @@ mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in); mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in); mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus); +void *reverce_memcpy(void *dest, const void *src, size_t len); +// int calc_size(mp_longint_impl_t x); #endif // MICROPY_INCLUDED_PY_OBJINT_H diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 1940b815386a6..c63de6d08f12b 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -43,6 +43,7 @@ const mp_obj_int_t mp_sys_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; #endif +/* mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { int delta = 1; if (!big_endian) { @@ -56,6 +57,50 @@ mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf } return mp_obj_new_int_from_ll(value); } +*/ +#define debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__); mp_printf(&mp_plat_print, "\n"); // mp_printf(&mp_plat_print, " | func:%s line:%d at %s\n", __FUNCTION__, __LINE__, __FILE__); +#define _debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__); + +mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, bool signd, size_t len, const byte *buf) { + union { + mp_longint_impl_t val; + byte buf[sizeof(mp_longint_impl_t)]; + } result = {0}; + + if (len > sizeof(result)) { + len = sizeof(result); + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("long int overflow")); + } + if (big_endian) { + reverce_memcpy(&result, buf, len); + } else { // little endian + memcpy(&result, buf, len); + } + if (signd) { + if ((sizeof(result) > len) && (result.buf[len - 1] & 0x80)) { + // Sign propagation + // x = 2 + // x.to_bytes(1, 'little', True) -> b'\x02' + // x.to_bytes(4, 'little', True) -> b'\x02\x00\x00\x00' + // x = -2 + // x.to_bytes(1, 'little', True) -> b'\xFE' + // x.to_bytes(4, 'little', True) -> b'\xFE\xFF\xFF\xFF' + debug_printf("result=0x%08X", result.val); + for (unsigned int i = 0; i < sizeof(result); i++) { + _debug_printf("\\%02X", result.buf[i]); + } + memset(result.buf + len, 0xFF, sizeof(result) - len); + debug_printf("\nresult=0x%08X", result.val); + for (unsigned int i = 0; i < sizeof(result); i++) { + _debug_printf("\\%02X", result.buf[i]); + } + debug_printf(""); + } + return mp_obj_new_int_from_ll(result.val); + } else { + return mp_obj_new_int_from_ull(result.val); + } +} bool mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) { assert(mp_obj_is_exact_type(self_in, &mp_type_int)); diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 6f2ea616c779c..90795e4948876 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -106,7 +106,7 @@ char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, return str; } -mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { +mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, bool signd, size_t len, const byte *buf) { mp_obj_int_t *o = mp_obj_int_new_mpz(); mpz_set_from_bytes(&o->mpz, big_endian, len, buf); return MP_OBJ_FROM_PTR(o); diff --git a/py/smallint.h b/py/smallint.h index 584e0018d1ba3..933fdf916946a 100644 --- a/py/smallint.h +++ b/py/smallint.h @@ -60,6 +60,7 @@ #endif #define MP_SMALL_INT_MAX ((mp_int_t)(~(MP_SMALL_INT_MIN))) +#define MP_SMALL_UINT_FITS(n) (((n) & ~MP_SMALL_INT_POSITIVE_MASK) == 0) // https://stackoverflow.com/a/4589384/1976323 // Number of bits in inttype_MAX, or in any (1<