Skip to content

Commit c4a88f2

Browse files
yoctopucedpgeorge
authored andcommitted
py/obj: Add functions to retrieve large integers from mp_obj_t.
This commit provides helpers to retrieve integer values from mp_obj_t when the content does not fit in a 32 bits integer, without risking an implicit wrap due to an int overflow. Signed-off-by: Yoctopuce dev <dev@yoctopuce.com>
1 parent 49159ef commit c4a88f2

File tree

6 files changed

+102
-0
lines changed

6 files changed

+102
-0
lines changed

ports/unix/coverage.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,26 @@ static mp_obj_t extra_coverage(void) {
488488
// mpz_set_from_float with 0 as argument
489489
mpz_set_from_float(&mpz, 0);
490490
mp_printf(&mp_plat_print, "%f\n", mpz_as_float(&mpz));
491+
492+
// convert a large integer value (stored in a mpz) to mp_uint_t and to ll;
493+
mp_obj_t obj_bigint = mp_obj_new_int_from_uint((mp_uint_t)0xdeadbeef);
494+
mp_printf(&mp_plat_print, "%x\n", mp_obj_get_uint(obj_bigint));
495+
obj_bigint = mp_obj_new_int_from_ll(0xc0ffee777c0ffeell);
496+
long long value_ll = mp_obj_get_ll(obj_bigint);
497+
mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll);
498+
499+
// convert a large integer value (stored via a struct object) to uint and to ll
500+
// `deadbeef` global is an uctypes.struct defined by extra_coverage.py
501+
obj_bigint = mp_load_global(MP_QSTR_deadbeef);
502+
mp_printf(&mp_plat_print, "%x\n", mp_obj_get_uint(obj_bigint));
503+
value_ll = mp_obj_get_ll(obj_bigint);
504+
mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll);
505+
506+
// convert a smaller integer value to mp_uint_t and to ll
507+
obj_bigint = mp_obj_new_int_from_uint(0xc0ffee);
508+
mp_printf(&mp_plat_print, "%x\n", mp_obj_get_uint(obj_bigint));
509+
value_ll = mp_obj_get_ll(obj_bigint);
510+
mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll);
491511
}
492512

493513
// runtime utils
@@ -530,6 +550,22 @@ static mp_obj_t extra_coverage(void) {
530550
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
531551
}
532552

553+
// mp_obj_get_uint from a non-int object (should raise exception)
554+
if (nlr_push(&nlr) == 0) {
555+
mp_obj_get_uint(mp_const_none);
556+
nlr_pop();
557+
} else {
558+
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
559+
}
560+
561+
// mp_obj_int_get_ll from a non-int object (should raise exception)
562+
if (nlr_push(&nlr) == 0) {
563+
mp_obj_get_ll(mp_const_none);
564+
nlr_pop();
565+
} else {
566+
mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val));
567+
}
568+
533569
// call mp_obj_new_exception_args (it's a part of the public C API and not used in the core)
534570
mp_obj_print_exception(&mp_plat_print, mp_obj_new_exception_args(&mp_type_ValueError, 0, NULL));
535571
}

py/obj.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,36 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) {
314314
return val;
315315
}
316316

317+
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
318+
mp_uint_t mp_obj_get_uint(mp_const_obj_t arg) {
319+
if (!mp_obj_is_exact_type(arg, &mp_type_int)) {
320+
mp_obj_t as_int = mp_unary_op(MP_UNARY_OP_INT_MAYBE, (mp_obj_t)arg);
321+
if (as_int == MP_OBJ_NULL) {
322+
mp_raise_TypeError_int_conversion(arg);
323+
}
324+
arg = as_int;
325+
}
326+
return mp_obj_int_get_uint_checked(arg);
327+
}
328+
329+
long long mp_obj_get_ll(mp_const_obj_t arg) {
330+
if (!mp_obj_is_exact_type(arg, &mp_type_int)) {
331+
mp_obj_t as_int = mp_unary_op(MP_UNARY_OP_INT_MAYBE, (mp_obj_t)arg);
332+
if (as_int == MP_OBJ_NULL) {
333+
mp_raise_TypeError_int_conversion(arg);
334+
}
335+
arg = as_int;
336+
}
337+
if (mp_obj_is_small_int(arg)) {
338+
return MP_OBJ_SMALL_INT_VALUE(arg);
339+
} else {
340+
long long res;
341+
mp_obj_int_to_bytes_impl((mp_obj_t)arg, MP_ENDIANNESS_BIG, sizeof(res), (byte *)&res);
342+
return res;
343+
}
344+
}
345+
#endif
346+
317347
mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) {
318348
if (mp_obj_is_int(arg)) {
319349
return mp_obj_int_get_truncated(arg);

py/obj.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,8 @@ static inline bool mp_obj_is_integer(mp_const_obj_t o) {
10511051
}
10521052

10531053
mp_int_t mp_obj_get_int(mp_const_obj_t arg);
1054+
mp_uint_t mp_obj_get_uint(mp_const_obj_t arg);
1055+
long long mp_obj_get_ll(mp_const_obj_t arg);
10541056
mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg);
10551057
bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value);
10561058
#if MICROPY_PY_BUILTINS_FLOAT

py/objint_longlong.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,22 @@ mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
295295
return mp_obj_int_get_truncated(self_in);
296296
}
297297

298+
mp_uint_t mp_obj_int_get_uint_checked(mp_const_obj_t self_in) {
299+
if (mp_obj_is_small_int(self_in)) {
300+
if (MP_OBJ_SMALL_INT_VALUE(self_in) >= 0) {
301+
return MP_OBJ_SMALL_INT_VALUE(self_in);
302+
}
303+
} else {
304+
const mp_obj_int_t *self = self_in;
305+
long long value = self->val;
306+
mp_uint_t truncated = (mp_uint_t)value;
307+
if (value >= 0 && (long long)truncated == value) {
308+
return truncated;
309+
}
310+
}
311+
mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("overflow converting long int to machine word"));
312+
}
313+
298314
#if MICROPY_PY_BUILTINS_FLOAT
299315
mp_float_t mp_obj_int_as_float_impl(mp_obj_t self_in) {
300316
assert(mp_obj_is_exact_type(self_in, &mp_type_int));

tests/ports/unix/extra_coverage.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66

77
import errno
88
import io
9+
import uctypes
10+
11+
# create an int-like variable used for coverage of `mp_obj_get_ll`
12+
buf = bytearray(b"\xde\xad\xbe\xef")
13+
struct = uctypes.struct(
14+
uctypes.addressof(buf),
15+
{"f32": uctypes.UINT32 | 0},
16+
uctypes.BIG_ENDIAN,
17+
)
18+
deadbeef = struct.f32
919

1020
data = extra_coverage()
1121

tests/ports/unix/extra_coverage.py.exp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ data
9494
1
9595
0
9696
0.000000
97+
deadbeef
98+
c0ffee777c0ffee
99+
deadbeef
100+
0deadbeef
101+
c0ffee
102+
000c0ffee
97103
# runtime utils
98104
TypeError: unsupported type for __abs__: 'str'
99105
TypeError: unsupported types for __divmod__: 'str', 'str'
@@ -102,6 +108,8 @@ TypeError: unsupported types for __divmod__: 'str', 'str'
102108
2
103109
OverflowError: overflow converting long int to machine word
104110
OverflowError: overflow converting long int to machine word
111+
TypeError: can't convert NoneType to int
112+
TypeError: can't convert NoneType to int
105113
ValueError:
106114
Warning: test
107115
# format float

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