From bec7bfb29d76f995dbf223c20f5d04ae1e33cee6 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sat, 21 Jan 2017 20:14:18 +0300 Subject: py/objint: from_bytes(): Implement "byteorder" param and arbitrary precision. If result guaranteedly fits in a small int, it is handled in objint.c. Otherwise, it is delegated to mp_obj_int_from_bytes_impl(), which should be implemented by individual objint_*.c, similar to mp_obj_int_to_bytes_impl(). --- py/objint.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'py/objint.c') diff --git a/py/objint.c b/py/objint.c index 5842a00a4..a61ed8e27 100644 --- a/py/objint.c +++ b/py/objint.c @@ -374,26 +374,33 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_uint_t op, mp_obj_t lhs_in, mp_obj_ // this is a classmethod STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) { - // TODO: Support long ints - // TODO: Support byteorder param // TODO: Support signed param (assumes signed=False at the moment) (void)n_args; - if (args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little)) { - mp_not_implemented(""); - } - // get the buffer info mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); - // convert the bytes to an integer - mp_uint_t value = 0; - for (const byte* buf = (const byte*)bufinfo.buf + bufinfo.len - 1; buf >= (byte*)bufinfo.buf; buf--) { - value = (value << 8) | *buf; - } + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + // If result guaranteedly fits in small int, use that + if (!MP_SMALL_INT_FITS(1 << (bufinfo.len * 8 - 1))) { + return mp_obj_int_from_bytes_impl(args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf); + } else + #endif + { + const byte* buf = (const byte*)bufinfo.buf; + int delta = 1; + if (args[2] == MP_OBJ_NEW_QSTR(MP_QSTR_little)) { + buf += bufinfo.len - 1; + delta = -1; + } - return mp_obj_new_int_from_uint(value); + mp_uint_t value = 0; + for (; bufinfo.len--; buf += delta) { + value = (value << 8) | *buf; + } + return mp_obj_new_int_from_uint(value); + } } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 3, 4, int_from_bytes); -- cgit v1.2.3 From eaa77455c37cf18670d181556e6d17e0b01c2267 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 25 Jan 2017 14:39:13 +1100 Subject: py/objint: Fix left-shift overflow in checking for large int. --- py/objint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'py/objint.c') diff --git a/py/objint.c b/py/objint.c index a61ed8e27..222aa1de7 100644 --- a/py/objint.c +++ b/py/objint.c @@ -383,7 +383,7 @@ STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) { #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE // If result guaranteedly fits in small int, use that - if (!MP_SMALL_INT_FITS(1 << (bufinfo.len * 8 - 1))) { + if (bufinfo.len >= sizeof(mp_uint_t) || !MP_SMALL_INT_FITS(1 << (bufinfo.len * 8 - 1))) { return mp_obj_int_from_bytes_impl(args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf); } else #endif -- cgit v1.2.3 From da36f5232dcf02c448ee9933e358b711cfe03f30 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 16 Feb 2017 16:41:43 +1100 Subject: py/objint: Convert mp_uint_t to size_t where appropriate. --- py/obj.h | 2 +- py/objint.c | 2 +- py/objint_longlong.c | 2 +- py/objint_mpz.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'py/objint.c') diff --git a/py/obj.h b/py/obj.h index 1b926ce14..1169a9095 100644 --- a/py/obj.h +++ b/py/obj.h @@ -607,7 +607,7 @@ static inline mp_obj_t mp_obj_new_bool(mp_int_t x) { return x ? mp_const_true : mp_obj_t mp_obj_new_cell(mp_obj_t obj); mp_obj_t mp_obj_new_int(mp_int_t value); mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value); -mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base); +mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base); mp_obj_t mp_obj_new_int_from_ll(long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_int_from_ull(unsigned long long val); // this must return a multi-precision integer object (or raise an overflow exception) mp_obj_t mp_obj_new_str(const char* data, size_t len, bool make_qstr_if_not_already); diff --git a/py/objint.c b/py/objint.c index 222aa1de7..2a7e3f3fd 100644 --- a/py/objint.c +++ b/py/objint.c @@ -291,7 +291,7 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { } // This is called only with strings whose value doesn't fit in SMALL_INT -mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base) { +mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { mp_raise_msg(&mp_type_OverflowError, "long int not supported in this build"); return mp_const_none; } diff --git a/py/objint_longlong.c b/py/objint_longlong.c index dbfb39809..b798c91cd 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -273,7 +273,7 @@ mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { } #endif -mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base) { +mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated // TODO check overflow mp_obj_int_t *o = m_new_obj(mp_obj_int_t); diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 2b27df4f6..2cdf22505 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -407,9 +407,9 @@ mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { } #endif -mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base) { +mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { mp_obj_int_t *o = mp_obj_int_new_mpz(); - mp_uint_t n = mpz_set_from_str(&o->mpz, *str, len, neg, base); + size_t n = mpz_set_from_str(&o->mpz, *str, len, neg, base); *str += n; return MP_OBJ_FROM_PTR(o); } -- cgit v1.2.3 From d1ae6ae080e1475b50aa2c6580d1ea588cfbdf64 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 14 Mar 2017 14:54:20 +1100 Subject: py/objint: Allow to print long-long ints without using the heap. Some stack is allocated to format ints, and when the int implementation uses long-long there should be additional stack allocated compared with the other cases. This patch uses the existing "fmt_int_t" type to determine the amount of stack to allocate. --- py/objint.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'py/objint.c') diff --git a/py/objint.c b/py/objint.c index 2a7e3f3fd..5aa6a95cc 100644 --- a/py/objint.c +++ b/py/objint.c @@ -127,11 +127,17 @@ mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { #undef MP_FLOAT_EXP_SHIFT_I32 #endif +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG +typedef mp_longint_impl_t fmt_int_t; +#else +typedef mp_int_t fmt_int_t; +#endif + void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; // The size of this buffer is rather arbitrary. If it's not large // enough, a dynamic one will be allocated. - char stack_buf[sizeof(mp_int_t) * 4]; + char stack_buf[sizeof(fmt_int_t) * 4]; char *buf = stack_buf; size_t buf_size = sizeof(stack_buf); size_t fmt_size; @@ -144,12 +150,6 @@ void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t } } -#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG -typedef mp_longint_impl_t fmt_int_t; -#else -typedef mp_int_t fmt_int_t; -#endif - STATIC const uint8_t log_base2_floor[] = { 0, 1, 1, 2, 2, 2, 2, 3, -- cgit v1.2.3 From c073519ec824145676edef88623496c1ded4fae5 Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 23 Mar 2017 23:51:35 +1100 Subject: py/objint: Handle special case of -0 when classifying fp as int. Otherwise -0.0 is classified as a bigint, which for builds without bigints will lead unexpectedly to an overflow. --- py/objint.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'py/objint.c') diff --git a/py/objint.c b/py/objint.c index 5aa6a95cc..ce091549d 100644 --- a/py/objint.c +++ b/py/objint.c @@ -103,7 +103,12 @@ mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE e |= u.i[MP_ENDIANNESS_BIG] != 0; #endif - e += ((1 << MP_FLOAT_EXP_BITS) - 1) << MP_FLOAT_EXP_SHIFT_I32; + if ((e & ~(1 << MP_FLOAT_SIGN_SHIFT_I32)) == 0) { + // handle case of -0 (when sign is set but rest of bits are zero) + e = 0; + } else { + e += ((1 << MP_FLOAT_EXP_BITS) - 1) << MP_FLOAT_EXP_SHIFT_I32; + } } else { e &= ~((1 << MP_FLOAT_EXP_SHIFT_I32) - 1); } -- cgit v1.2.3 From 6b341075376705ee1fe9e003b76b09afa59778f4 Mon Sep 17 00:00:00 2001 From: Damien George Date: Sat, 25 Mar 2017 19:48:18 +1100 Subject: py: Change mp_uint_t to size_t for mp_obj_str_get_data len arg. --- py/builtinevex.c | 4 ++-- py/builtinimport.c | 6 +++--- py/modbuiltins.c | 6 +++--- py/obj.h | 2 +- py/objcomplex.c | 2 +- py/objfloat.c | 2 +- py/objfun.c | 2 +- py/objint.c | 4 ++-- py/objstr.c | 12 ++++++------ py/repl.c | 6 +++--- py/runtime.c | 2 +- 11 files changed, 24 insertions(+), 24 deletions(-) (limited to 'py/objint.c') diff --git a/py/builtinevex.c b/py/builtinevex.c index 89fcc2fe1..d9a3833cc 100644 --- a/py/builtinevex.c +++ b/py/builtinevex.c @@ -78,7 +78,7 @@ STATIC mp_obj_t mp_builtin_compile(size_t n_args, const mp_obj_t *args) { (void)n_args; // get the source - mp_uint_t str_len; + size_t str_len; const char *str = mp_obj_str_get_data(args[0], &str_len); // get the filename @@ -128,7 +128,7 @@ STATIC mp_obj_t eval_exec_helper(size_t n_args, const mp_obj_t *args, mp_parse_i } #endif - mp_uint_t str_len; + size_t str_len; const char *str = mp_obj_str_get_data(args[0], &str_len); // create the lexer diff --git a/py/builtinimport.c b/py/builtinimport.c index 8101d633f..cf17d5305 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -111,7 +111,7 @@ STATIC mp_import_stat_t find_file(const char *file_str, uint file_len, vstr_t *d // go through each path looking for a directory or file for (mp_uint_t i = 0; i < path_num; i++) { vstr_reset(dest); - mp_uint_t p_len; + size_t p_len; const char *p = mp_obj_str_get_data(path_items[i], &p_len); if (p_len > 0) { vstr_add_strn(dest, p, p_len); @@ -265,7 +265,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { } } - mp_uint_t mod_len; + size_t mod_len; const char *mod_str = mp_obj_str_get_data(module_name, &mod_len); if (level != 0) { @@ -296,7 +296,7 @@ mp_obj_t mp_builtin___import__(size_t n_args, const mp_obj_t *args) { DEBUG_printf("\n"); #endif - mp_uint_t this_name_l; + size_t this_name_l; const char *this_name = mp_obj_str_get_data(this_name_q, &this_name_l); const char *p = this_name + this_name_l; diff --git a/py/modbuiltins.c b/py/modbuiltins.c index f1d703a6d..e8119456d 100644 --- a/py/modbuiltins.c +++ b/py/modbuiltins.c @@ -336,7 +336,7 @@ STATIC mp_obj_t mp_builtin_oct(mp_obj_t o_in) { MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_oct_obj, mp_builtin_oct); STATIC mp_obj_t mp_builtin_ord(mp_obj_t o_in) { - mp_uint_t len; + size_t len; const char *str = mp_obj_str_get_data(o_in, &len); #if MICROPY_PY_BUILTINS_STR_UNICODE if (MP_OBJ_IS_STR(o_in)) { @@ -397,9 +397,9 @@ STATIC mp_obj_t mp_builtin_print(size_t n_args, const mp_obj_t *args, mp_map_t * mp_map_elem_t *sep_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_sep), MP_MAP_LOOKUP); mp_map_elem_t *end_elem = mp_map_lookup(kwargs, MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_MAP_LOOKUP); const char *sep_data = " "; - mp_uint_t sep_len = 1; + size_t sep_len = 1; const char *end_data = "\n"; - mp_uint_t end_len = 1; + size_t end_len = 1; if (sep_elem != NULL && sep_elem->value != mp_const_none) { sep_data = mp_obj_str_get_data(sep_elem->value, &sep_len); } diff --git a/py/obj.h b/py/obj.h index 65543b785..580b814a8 100644 --- a/py/obj.h +++ b/py/obj.h @@ -712,7 +712,7 @@ void mp_init_emergency_exception_buf(void); bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2); qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway convert the string to a qstr const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated -const char *mp_obj_str_get_data(mp_obj_t self_in, mp_uint_t *len); +const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len); mp_obj_t mp_obj_str_intern(mp_obj_t str); void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes); diff --git a/py/objcomplex.c b/py/objcomplex.c index 426e76e5f..8118fb813 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -80,7 +80,7 @@ STATIC mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, si case 1: if (MP_OBJ_IS_STR(args[0])) { // a string, parse it - mp_uint_t l; + size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_decimal(s, l, true, true, NULL); } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) { diff --git a/py/objfloat.c b/py/objfloat.c index 9292490a9..6d80d6c0e 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -89,7 +89,7 @@ STATIC mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size default: if (MP_OBJ_IS_STR(args[0])) { // a string, parse it - mp_uint_t l; + size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_decimal(s, l, false, false, NULL); } else if (mp_obj_is_float(args[0])) { diff --git a/py/objfun.c b/py/objfun.c index 2ce33cb21..08d031c8d 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -501,7 +501,7 @@ STATIC mp_uint_t convert_obj_for_inline_asm(mp_obj_t obj) { return mp_obj_int_get_truncated(obj); } else if (MP_OBJ_IS_STR(obj)) { // pointer to the string (it's probably constant though!) - mp_uint_t l; + size_t l; return (mp_uint_t)mp_obj_str_get_data(obj, &l); } else { mp_obj_type_t *type = mp_obj_get_type(obj); diff --git a/py/objint.c b/py/objint.c index ce091549d..2e8fe4f22 100644 --- a/py/objint.c +++ b/py/objint.c @@ -56,7 +56,7 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, return args[0]; } else if (MP_OBJ_IS_STR_OR_BYTES(args[0])) { // a string, parse it - mp_uint_t l; + size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_integer(s, l, 0, NULL); #if MICROPY_PY_BUILTINS_FLOAT @@ -72,7 +72,7 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, default: { // should be a string, parse it // TODO proper error checking of argument types - mp_uint_t l; + size_t l; const char *s = mp_obj_str_get_data(args[0], &l); return mp_parse_num_integer(s, l, mp_obj_get_int(args[1]), NULL); } diff --git a/py/objstr.c b/py/objstr.c index 682bd2693..60a26d45b 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -513,7 +513,7 @@ mp_obj_t mp_obj_str_split(size_t n_args, const mp_obj_t *args) { bad_implicit_conversion(sep); } - mp_uint_t sep_len; + size_t sep_len; const char *sep_str = mp_obj_str_get_data(sep, &sep_len); if (sep_len == 0) { @@ -611,7 +611,7 @@ STATIC mp_obj_t str_rsplit(size_t n_args, const mp_obj_t *args) { if (sep == mp_const_none) { mp_not_implemented("rsplit(None,n)"); } else { - mp_uint_t sep_len; + size_t sep_len; const char *sep_str = mp_obj_str_get_data(sep, &sep_len); if (sep_len == 0) { @@ -1306,12 +1306,12 @@ STATIC vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar switch (type) { case '\0': // no explicit format type implies 's' case 's': { - mp_uint_t slen; + size_t slen; const char *s = mp_obj_str_get_data(arg, &slen); if (precision < 0) { precision = slen; } - if (slen > (mp_uint_t)precision) { + if (slen > (size_t)precision) { slen = precision; } mp_print_strn(&print, s, slen, flags, fill, width); @@ -1452,7 +1452,7 @@ not_enough_args: switch (*str) { case 'c': if (MP_OBJ_IS_STR(arg)) { - mp_uint_t slen; + size_t slen; const char *s = mp_obj_str_get_data(arg, &slen); if (slen != 1) { mp_raise_TypeError("%%c requires int or char"); @@ -2097,7 +2097,7 @@ const char *mp_obj_str_get_str(mp_obj_t self_in) { } } -const char *mp_obj_str_get_data(mp_obj_t self_in, mp_uint_t *len) { +const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len) { if (MP_OBJ_IS_STR_OR_BYTES(self_in)) { GET_STR_DATA_LEN(self_in, s, l); *len = l; diff --git a/py/repl.c b/py/repl.c index 997d80005..6d8f7cca4 100644 --- a/py/repl.c +++ b/py/repl.c @@ -153,7 +153,7 @@ mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t mp_obj_t obj = MP_OBJ_NULL; for (mp_uint_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - mp_uint_t d_len; + size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len == d_len && strncmp(s_start, d_str, d_len) == 0) { obj = dict->map.table[i].value; @@ -197,7 +197,7 @@ mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t mp_uint_t match_len = 0; for (mp_uint_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - mp_uint_t d_len; + size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { if (match_str == NULL) { @@ -247,7 +247,7 @@ mp_uint_t mp_repl_autocomplete(const char *str, mp_uint_t len, const mp_print_t int line_len = MAX_LINE_LEN; // force a newline for first word for (mp_uint_t i = 0; i < dict->map.alloc; i++) { if (MP_MAP_SLOT_IS_FILLED(&dict->map, i)) { - mp_uint_t d_len; + size_t d_len; const char *d_str = mp_obj_str_get_data(dict->map.table[i].key, &d_len); if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; diff --git a/py/runtime.c b/py/runtime.c index 73886e10f..1df6740b2 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1330,7 +1330,7 @@ import_error: } mp_load_method_maybe(module, MP_QSTR___name__, dest); - mp_uint_t pkg_name_len; + size_t pkg_name_len; const char *pkg_name = mp_obj_str_get_data(dest[0], &pkg_name_len); const uint dot_name_len = pkg_name_len + 1 + qstr_len(name); -- cgit v1.2.3 From fc245d1ca4367f9876ac32c7e08e169da7db79b9 Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 4 Apr 2017 16:45:49 +1000 Subject: py/objint: Consolidate mp_obj_new_int_from_float to one implementation. This reduces code duplication and allows to make mp_classify_fp_as_int static, which reduces code size. --- py/objint.c | 56 ++++++++++++++++++++++++++++++++++------------------ py/objint.h | 11 +++-------- py/objint_longlong.c | 20 ------------------- py/objint_mpz.c | 22 +-------------------- 4 files changed, 41 insertions(+), 68 deletions(-) (limited to 'py/objint.c') diff --git a/py/objint.c b/py/objint.c index 2e8fe4f22..46f9b1666 100644 --- a/py/objint.c +++ b/py/objint.c @@ -80,7 +80,14 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args, } #if MICROPY_PY_BUILTINS_FLOAT -mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { + +typedef enum { + MP_FP_CLASS_FIT_SMALLINT, + MP_FP_CLASS_FIT_LONGINT, + MP_FP_CLASS_OVERFLOW +} mp_fp_as_int_class_t; + +STATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { union { mp_float_t f; #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT @@ -130,6 +137,35 @@ mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { } #undef MP_FLOAT_SIGN_SHIFT_I32 #undef MP_FLOAT_EXP_SHIFT_I32 + +mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { + int cl = fpclassify(val); + if (cl == FP_INFINITE) { + nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "can't convert inf to int")); + } else if (cl == FP_NAN) { + mp_raise_ValueError("can't convert NaN to int"); + } else { + mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val); + if (icl == MP_FP_CLASS_FIT_SMALLINT) { + return MP_OBJ_NEW_SMALL_INT((mp_int_t)val); + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ + } else { + mp_obj_int_t *o = mp_obj_int_new_mpz(); + mpz_set_from_float(&o->mpz, val); + return MP_OBJ_FROM_PTR(o); + } + #else + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG + } else if (icl == MP_FP_CLASS_FIT_LONGINT) { + return mp_obj_new_int_from_ll((long long)val); + #endif + } else { + mp_raise_ValueError("float too big"); + } + #endif + } +} + #endif #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG @@ -323,24 +359,6 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { return mp_const_none; } -#if MICROPY_PY_BUILTINS_FLOAT -mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { - int cl = fpclassify(val); - if (cl == FP_INFINITE) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int")); - } else if (cl == FP_NAN) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int")); - } else { - mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val); - if (icl == MP_FP_CLASS_FIT_SMALLINT) { - return MP_OBJ_NEW_SMALL_INT((mp_int_t)val); - } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "float too big")); - } - } -} -#endif - mp_obj_t mp_obj_new_int(mp_int_t value) { if (MP_SMALL_INT_FITS(value)) { return MP_OBJ_NEW_SMALL_INT(value); diff --git a/py/objint.h b/py/objint.h index 7205761ad..da56c1862 100644 --- a/py/objint.h +++ b/py/objint.h @@ -41,18 +41,13 @@ typedef struct _mp_obj_int_t { extern const mp_obj_int_t mp_maxsize_obj; #if MICROPY_PY_BUILTINS_FLOAT -typedef enum { - MP_FP_CLASS_FIT_SMALLINT, - MP_FP_CLASS_FIT_LONGINT, - MP_FP_CLASS_OVERFLOW -} mp_fp_as_int_class_t; - -mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val); mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in); -#endif // MICROPY_PY_BUILTINS_FLOAT +#endif size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma); +mp_obj_int_t *mp_obj_int_new_mpz(void); + void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind); char *mp_obj_int_formatted(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); diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 4ab49f337..540cfebd0 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -263,26 +263,6 @@ mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { return o; } -#if MICROPY_PY_BUILTINS_FLOAT -mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { - int cl = fpclassify(val); - if (cl == FP_INFINITE) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int")); - } else if (cl == FP_NAN) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int")); - } else { - mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val); - if (icl == MP_FP_CLASS_FIT_SMALLINT) { - return MP_OBJ_NEW_SMALL_INT((mp_int_t)val); - } else if (icl == MP_FP_CLASS_FIT_LONGINT) { - return mp_obj_new_int_from_ll((long long)val); - } else { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "float too big")); - } - } -} -#endif - mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated // TODO check overflow diff --git a/py/objint_mpz.c b/py/objint_mpz.c index ca989e8ad..2353bd8d6 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -74,7 +74,7 @@ const mp_obj_int_t mp_maxsize_obj = { #undef NUM_DIG #endif -STATIC mp_obj_int_t *mp_obj_int_new_mpz(void) { +mp_obj_int_t *mp_obj_int_new_mpz(void) { mp_obj_int_t *o = m_new_obj(mp_obj_int_t); o->base.type = &mp_type_int; mpz_init_zero(&o->mpz); @@ -387,26 +387,6 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) { return mp_obj_new_int_from_ull(value); } -#if MICROPY_PY_BUILTINS_FLOAT -mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { - int cl = fpclassify(val); - if (cl == FP_INFINITE) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int")); - } else if (cl == FP_NAN) { - nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int")); - } else { - mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val); - if (icl == MP_FP_CLASS_FIT_SMALLINT) { - return MP_OBJ_NEW_SMALL_INT((mp_int_t)val); - } else { - mp_obj_int_t *o = mp_obj_int_new_mpz(); - mpz_set_from_float(&o->mpz, val); - return MP_OBJ_FROM_PTR(o); - } - } -} -#endif - mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { mp_obj_int_t *o = mp_obj_int_new_mpz(); size_t n = mpz_set_from_str(&o->mpz, *str, len, neg, base); -- cgit v1.2.3 From f66df1efc85fe9fc7fd0b2125792d02001de48bb Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Apr 2017 15:16:09 +1000 Subject: py/objint: Extract small int value directly because type is known. --- py/objint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'py/objint.c') diff --git a/py/objint.c b/py/objint.c index 46f9b1666..719fd4970 100644 --- a/py/objint.c +++ b/py/objint.c @@ -224,7 +224,7 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co fmt_int_t num; if (MP_OBJ_IS_SMALL_INT(self_in)) { // A small int; get the integer value to format. - num = mp_obj_get_int(self_in); + num = MP_OBJ_SMALL_INT_VALUE(self_in); #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE } else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) { // Not a small int. -- cgit v1.2.3 From e31fbd9b41315963aaca732e7585fc4cb10ccbcd Mon Sep 17 00:00:00 2001 From: Damien George Date: Tue, 11 Apr 2017 15:18:35 +1000 Subject: py/objint: Use unsigned arithmetic when formatting an integer. Otherwise the edge case of the most negative integer value will not convert correctly. --- py/objint.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'py/objint.c') diff --git a/py/objint.c b/py/objint.c index 719fd4970..99c54a310 100644 --- a/py/objint.c +++ b/py/objint.c @@ -170,8 +170,10 @@ mp_obj_t mp_obj_new_int_from_float(mp_float_t val) { #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG typedef mp_longint_impl_t fmt_int_t; +typedef unsigned long long fmt_uint_t; #else typedef mp_int_t fmt_int_t; +typedef mp_uint_t fmt_uint_t; #endif void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -265,8 +267,9 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co *(--b) = '0'; } else { do { - int c = num % base; - num /= base; + // The cast to fmt_uint_t is because num is positive and we want unsigned arithmetic + int c = (fmt_uint_t)num % base; + num = (fmt_uint_t)num / base; if (c >= 10) { c += base_char - 10; } else { -- cgit v1.2.3 From 58bb73e010301235b32c3b81575af21cca55f2a7 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 5 May 2017 21:42:39 +1000 Subject: py/objint: In int.from_bytes, only create big-int if really needed. This patch ensures that int.from_bytes only creates a big-int if necessary, by checking the value for a small-int overflow as it's being parsed. --- py/objint.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'py/objint.c') diff --git a/py/objint.c b/py/objint.c index 99c54a310..bda9c46cf 100644 --- a/py/objint.c +++ b/py/objint.c @@ -407,26 +407,25 @@ 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); - #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE - // If result guaranteedly fits in small int, use that - if (bufinfo.len >= sizeof(mp_uint_t) || !MP_SMALL_INT_FITS(1 << (bufinfo.len * 8 - 1))) { - return mp_obj_int_from_bytes_impl(args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf); - } else - #endif - { - const byte* buf = (const byte*)bufinfo.buf; - int delta = 1; - if (args[2] == MP_OBJ_NEW_QSTR(MP_QSTR_little)) { - buf += bufinfo.len - 1; - delta = -1; - } + const byte* buf = (const byte*)bufinfo.buf; + int delta = 1; + if (args[2] == MP_OBJ_NEW_QSTR(MP_QSTR_little)) { + buf += bufinfo.len - 1; + delta = -1; + } - mp_uint_t value = 0; - for (; bufinfo.len--; buf += delta) { - value = (value << 8) | *buf; + mp_uint_t value = 0; + size_t len = bufinfo.len; + for (; len--; buf += delta) { + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE + if (value > (MP_SMALL_INT_MAX >> 8)) { + // Result will overflow a small-int so construct a big-int + return mp_obj_int_from_bytes_impl(args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf); } - return mp_obj_new_int_from_uint(value); + #endif + value = (value << 8) | *buf; } + return mp_obj_new_int_from_uint(value); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 3, 4, int_from_bytes); -- cgit v1.2.3