Skip to content

Commit 8f7925d

Browse files
committed
py/objint.c: Code review of int_from_bytes().
Support signed param: result = int.int_from_bytes(bytearray(), order='big'|'little', signed=False|True) Signed-off-by: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
1 parent 8987b39 commit 8f7925d

File tree

6 files changed

+152
-4
lines changed

6 files changed

+152
-4
lines changed

ports/esp32/mpconfigport.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@
6161
#define MICROPY_ENABLE_GC (1)
6262
#define MICROPY_STACK_CHECK_MARGIN (1024)
6363
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
64-
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
65-
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)
64+
#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) // (MICROPY_LONGINT_IMPL_MPZ)
65+
#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL + 1)
6666
#define MICROPY_WARNINGS (1)
6767
#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
6868
#define MICROPY_STREAMS_POSIX_API (1)

py/objint.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
#include <math.h>
4040
#endif
4141

42+
#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__);
43+
#define _debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__);
44+
4245
// This dispatcher function is expected to be independent of the implementation of long int
4346
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) {
4447
(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
387390
return MP_OBJ_NULL; // op not supported
388391
}
389392

393+
/*
390394
// this is a classmethod
391395
static mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) {
392396
// 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) {
416420
}
417421
return mp_obj_new_int_from_uint(value);
418422
}
423+
*/
424+
/*
425+
int calc_size(mp_longint_impl_t x) {
426+
int size = 0;
427+
if (x < 0) {
428+
x = -x;
429+
}
430+
do {
431+
x >>= 8;
432+
size++;
433+
} while (x);
434+
return size;
435+
}
436+
*/
437+
void *reverce_memcpy(void *dest, const void *src, size_t len) {
438+
char *d = (char *)dest + len - 1;
439+
const char *s = src;
440+
while (len--) {
441+
*d-- = *s++;
442+
}
443+
return dest;
444+
}
445+
446+
// this is a classmethod
447+
// result = int.int_from_bytes(bytearray(), order='big', signed=False)
448+
static mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) {
449+
mp_buffer_info_t bufinfo;
450+
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
451+
bool big_endian = (n_args < 3) || (args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little));
452+
bool signd = (n_args > 3) && mp_obj_is_true(args[3]);
453+
454+
// debug_printf("mp_obj_is_bool(args[3])=%d", mp_obj_is_bool(args[3]));
455+
// 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);
456+
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
457+
if ((1ULL << (bufinfo.len * 8 - 2)) > (MP_SMALL_INT_MAX + 1)) {
458+
debug_printf("//1 Result will overflow a small-int so construct a big-int");
459+
debug_printf("big_endian:%d signed:%d bufinfo.len:%d", big_endian, signd, bufinfo.len);
460+
return mp_obj_int_from_bytes_impl(big_endian, signd, bufinfo.len, bufinfo.buf);
461+
}
462+
#endif
463+
464+
union {
465+
mp_int_t ival;
466+
mp_uint_t uval;
467+
byte buf[sizeof(mp_uint_t)];
468+
} result = {0};
469+
470+
if (bufinfo.len > sizeof(result)) {
471+
mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small-int too large"));
472+
bufinfo.len = sizeof(result);
473+
}
474+
475+
if (big_endian) {
476+
reverce_memcpy(&result.uval, bufinfo.buf, bufinfo.len);
477+
} else { // little endian
478+
memcpy(&result.uval, bufinfo.buf, bufinfo.len);
479+
}
480+
if (signd) {
481+
if ((sizeof(result) > bufinfo.len) && (result.buf[bufinfo.len - 1] & 0x80)) {
482+
// Sign propagation
483+
// x = 2
484+
// x.to_bytes(1, 'little', True) -> b'\x02'
485+
// x.to_bytes(4, 'little', True) -> b'\x02\x00\x00\x00'
486+
// x = -2
487+
// x.to_bytes(1, 'little', True) -> b'\xFE'
488+
// x.to_bytes(4, 'little', True) -> b'\xFE\xFF\xFF\xFF'
489+
debug_printf("result=0x%08X", result.uval);
490+
for (unsigned int i = 0; i < sizeof(result); i++) {
491+
_debug_printf("\\%02X", result.buf[i]);
492+
}
493+
memset(result.buf + bufinfo.len, 0xFF, sizeof(result) - bufinfo.len);
494+
debug_printf("\nresult=0x%08X", result.uval);
495+
for (unsigned int i = 0; i < sizeof(result); i++) {
496+
_debug_printf("\\%02X", result.buf[i]);
497+
}
498+
debug_printf("");
499+
}
500+
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
501+
// 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);
502+
if (!MP_SMALL_INT_FITS(result.ival)) {
503+
debug_printf("//2 Result will overflow a small-int so construct a big-int");
504+
return mp_obj_int_from_bytes_impl(big_endian, signd, bufinfo.len, bufinfo.buf);
505+
}
506+
#endif
507+
return mp_obj_new_int(result.ival);
508+
} else {
509+
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
510+
// 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);
511+
if (!MP_SMALL_UINT_FITS(result.uval)) {
512+
debug_printf("//3 Result will overflow a small-int so construct a big-int");
513+
return mp_obj_int_from_bytes_impl(big_endian, signd, bufinfo.len, bufinfo.buf);
514+
}
515+
#endif
516+
return mp_obj_new_int_from_uint(result.uval);
517+
}
518+
}
419519

420520
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(int_from_bytes_fun_obj, 2, 4, int_from_bytes);
421521
static MP_DEFINE_CONST_CLASSMETHOD_OBJ(int_from_bytes_obj, MP_ROM_PTR(&int_from_bytes_fun_obj));

py/objint.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,15 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co
5454
char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size, mp_const_obj_t self_in,
5555
int base, const char *prefix, char base_char, char comma);
5656
mp_int_t mp_obj_int_hash(mp_obj_t self_in);
57-
mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf);
57+
mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, bool signd, size_t len, const byte *buf);
5858
// Returns true if 'self_in' fit into 'len' bytes of 'buf' without overflowing, 'buf' is truncated otherwise.
5959
bool mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf);
6060
int mp_obj_int_sign(mp_obj_t self_in);
6161
mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in);
6262
mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in);
6363
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);
6464
mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus);
65+
void *reverce_memcpy(void *dest, const void *src, size_t len);
66+
// int calc_size(mp_longint_impl_t x);
6567

6668
#endif // MICROPY_INCLUDED_PY_OBJINT_H

py/objint_longlong.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
const mp_obj_int_t mp_sys_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX};
4444
#endif
4545

46+
/*
4647
mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) {
4748
int delta = 1;
4849
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
5657
}
5758
return mp_obj_new_int_from_ll(value);
5859
}
60+
*/
61+
#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__);
62+
#define _debug_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__);
63+
64+
mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, bool signd, size_t len, const byte *buf) {
65+
union {
66+
mp_longint_impl_t val;
67+
byte buf[sizeof(mp_longint_impl_t)];
68+
} result = {0};
69+
70+
if (len > sizeof(result)) {
71+
len = sizeof(result);
72+
mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("long int overflow"));
73+
}
74+
if (big_endian) {
75+
reverce_memcpy(&result, buf, len);
76+
} else { // little endian
77+
memcpy(&result, buf, len);
78+
}
79+
if (signd) {
80+
if ((sizeof(result) > len) && (result.buf[len - 1] & 0x80)) {
81+
// Sign propagation
82+
// x = 2
83+
// x.to_bytes(1, 'little', True) -> b'\x02'
84+
// x.to_bytes(4, 'little', True) -> b'\x02\x00\x00\x00'
85+
// x = -2
86+
// x.to_bytes(1, 'little', True) -> b'\xFE'
87+
// x.to_bytes(4, 'little', True) -> b'\xFE\xFF\xFF\xFF'
88+
debug_printf("result=0x%08X", result.val);
89+
for (unsigned int i = 0; i < sizeof(result); i++) {
90+
_debug_printf("\\%02X", result.buf[i]);
91+
}
92+
memset(result.buf + len, 0xFF, sizeof(result) - len);
93+
debug_printf("\nresult=0x%08X", result.val);
94+
for (unsigned int i = 0; i < sizeof(result); i++) {
95+
_debug_printf("\\%02X", result.buf[i]);
96+
}
97+
debug_printf("");
98+
}
99+
return mp_obj_new_int_from_ll(result.val);
100+
} else {
101+
return mp_obj_new_int_from_ull(result.val);
102+
}
103+
}
59104

60105
bool mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf) {
61106
assert(mp_obj_is_exact_type(self_in, &mp_type_int));

py/objint_mpz.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size,
106106
return str;
107107
}
108108

109-
mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) {
109+
mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, bool signd, size_t len, const byte *buf) {
110110
mp_obj_int_t *o = mp_obj_int_new_mpz();
111111
mpz_set_from_bytes(&o->mpz, big_endian, len, buf);
112112
return MP_OBJ_FROM_PTR(o);

py/smallint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#endif
6161

6262
#define MP_SMALL_INT_MAX ((mp_int_t)(~(MP_SMALL_INT_MIN)))
63+
#define MP_SMALL_UINT_FITS(n) (((n) & ~MP_SMALL_INT_POSITIVE_MASK) == 0)
6364

6465
// https://stackoverflow.com/a/4589384/1976323
6566
// Number of bits in inttype_MAX, or in any (1<<k)-1 where 0 <= k < 2040

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy