Skip to content

Commit 83fe7b1

Browse files
committed
Add term_to_bigint and term_is_bigint
Replace duplicated code with new functions in term.h. Signed-off-by: Davide Bettio <davide@uninstall.it>
1 parent 1725da5 commit 83fe7b1

File tree

5 files changed

+109
-47
lines changed

5 files changed

+109
-47
lines changed

src/libAtomVM/bif.c

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,6 @@
7979
#define INT64_MAX_AS_AVM_FLOAT 9223372036854775295.0 // 0x43DFFFFFFFFFFFFF = 2^62 * 1.1...1b
8080
#endif
8181

82-
// intn.h and term.h headers are decoupled. We check here that sign enum values are matching.
83-
_Static_assert(
84-
(int) TermPositiveInteger == (int) IntNPositiveInteger, "term/intn definition mismatch");
85-
_Static_assert(
86-
(int) TermNegativeInteger == (int) IntNNegativeInteger, "term/intn definition mismatch");
87-
8882
static term make_bigint(Context *ctx, uint32_t fail_label, uint32_t live,
8983
const intn_digit_t bigres[], size_t bigres_len, intn_integer_sign_t sign);
9084

@@ -842,11 +836,9 @@ static term make_bigint(Context *ctx, uint32_t fail_label, uint32_t live,
842836
static void conv_term_to_bigint(term arg1, intn_digit_t *tmp_buf1, const intn_digit_t **b1,
843837
size_t *b1_len, intn_integer_sign_t *b1_sign)
844838
{
845-
if (term_is_boxed_integer(arg1)
846-
&& (term_boxed_size(arg1) > (INTN_INT64_LEN * sizeof(intn_digit_t)) / sizeof(term))) {
847-
*b1 = term_intn_data(arg1);
848-
*b1_len = term_intn_size(arg1) * (sizeof(term) / sizeof(intn_digit_t));
849-
*b1_sign = (intn_integer_sign_t) term_boxed_integer_sign(arg1);
839+
if (term_is_bigint(arg1)) {
840+
term_to_bigint(arg1, b1, b1_len, b1_sign);
841+
850842
} else {
851843
avm_int64_t i64 = term_maybe_unbox_int64(arg1);
852844
intn_from_int64(i64, tmp_buf1, b1_sign);
@@ -1146,10 +1138,10 @@ term bif_erlang_div_2(Context *ctx, uint32_t fail_label, int live, term arg1, te
11461138
// that just copies the given term but changes the sign
11471139
static term neg_bigint(Context *ctx, uint32_t fail_label, uint32_t live, term arg1)
11481140
{
1149-
// update when updating conv_term_to_bigint
1150-
intn_digit_t *m = term_intn_data(arg1);
1151-
size_t m_len = term_intn_size(arg1) * (sizeof(term) / sizeof(intn_digit_t));
1152-
intn_integer_sign_t m_sign = (intn_integer_sign_t) term_boxed_integer_sign(arg1);
1141+
const intn_digit_t *m;
1142+
size_t m_len;
1143+
intn_integer_sign_t m_sign;
1144+
term_to_bigint(arg1, &m, &m_len, &m_sign);
11531145

11541146
intn_digit_t tmp_copy[INTN_MAX_RES_LEN];
11551147
memcpy(tmp_copy, m, m_len * sizeof(intn_digit_t));
@@ -1242,9 +1234,10 @@ term bif_erlang_neg_1(Context *ctx, uint32_t fail_label, int live, term arg1)
12421234
// that just copies the given term but changes the sign
12431235
static term abs_bigint(Context *ctx, uint32_t fail_label, uint32_t live, term arg1)
12441236
{
1245-
// update when updating conv_term_to_bigint
1246-
intn_digit_t *m = term_intn_data(arg1);
1247-
size_t m_len = term_intn_size(arg1) * (sizeof(term) / sizeof(intn_digit_t));
1237+
const intn_digit_t *m;
1238+
size_t m_len;
1239+
intn_integer_sign_t discarded_sign;
1240+
term_to_bigint(arg1, &m, &m_len, &discarded_sign);
12481241

12491242
intn_digit_t tmp_copy[INTN_MAX_RES_LEN];
12501243
memcpy(tmp_copy, m, m_len * sizeof(intn_digit_t));

src/libAtomVM/externalterm.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,14 +234,12 @@ static int serialize_term(uint8_t *buf, term t, GlobalContext *glb)
234234
return SMALL_BIG_EXT_BASE_SIZE + num_bytes;
235235
}
236236
} else {
237-
size_t intn_size = term_intn_size(t);
238-
size_t digits_per_term = sizeof(term) / sizeof(intn_digit_t);
239-
size_t bigint_len = intn_size * digits_per_term;
240-
const intn_digit_t *bigint = (const intn_digit_t *) term_intn_data(t);
237+
const intn_digit_t *bigint;
238+
size_t bigint_len;
239+
intn_integer_sign_t sign;
240+
term_to_bigint(t, &bigint, &bigint_len, &sign);
241241
size_t num_bytes = intn_required_unsigned_integer_bytes(bigint, bigint_len);
242242
if (buf != NULL) {
243-
intn_integer_sign_t sign = (intn_integer_sign_t) term_boxed_integer_sign(t);
244-
245243
buf[0] = SMALL_BIG_EXT;
246244
buf[1] = num_bytes;
247245
buf[2] = sign == IntNNegativeInteger ? 0x01 : 0x00;

src/libAtomVM/nifs.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2396,12 +2396,11 @@ static term integer_to_buf(Context *ctx, int argc, term argv[], char *tmp_buf, s
23962396
}
23972397
#endif
23982398
default: {
2399-
size_t boxed_size = term_intn_size(value);
2400-
size_t digits_per_term = sizeof(term) / sizeof(intn_digit_t);
2401-
const intn_digit_t *intn_buf = (const intn_digit_t *) term_intn_data(value);
2402-
intn_integer_sign_t sign = (intn_integer_sign_t) term_boxed_integer_sign(value);
2403-
*int_buf
2404-
= intn_to_string(intn_buf, boxed_size * digits_per_term, sign, base, int_len);
2399+
const intn_digit_t *intn_buf;
2400+
size_t intn_buf_len;
2401+
intn_integer_sign_t sign;
2402+
term_to_bigint(value, &intn_buf, &intn_buf_len, &sign);
2403+
*int_buf = intn_to_string(intn_buf, intn_buf_len, sign, base, int_len);
24052404
*needs_cleanup = true;
24062405
}
24072406
}

src/libAtomVM/term.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -420,13 +420,12 @@ int term_funprint(PrinterFun *fun, term t, const GlobalContext *global)
420420
return fun->print(fun, AVM_INT64_FMT, term_unbox_int64(t));
421421
#endif
422422
default: {
423-
size_t digits_per_term = sizeof(term) / sizeof(intn_digit_t);
424-
size_t boxed_size = term_intn_size(t);
425-
const intn_digit_t *intn_data = (const intn_digit_t *) term_intn_data(t);
426-
intn_integer_sign_t sign = (intn_integer_sign_t) term_boxed_integer_sign(t);
423+
const intn_digit_t *intn_data;
424+
size_t intn_data_len;
425+
intn_integer_sign_t sign;
426+
term_to_bigint(t, &intn_data, &intn_data_len, &sign);
427427
size_t unused_s_len;
428-
char *s = intn_to_string(
429-
intn_data, boxed_size * digits_per_term, sign, 10, &unused_s_len);
428+
char *s = intn_to_string(intn_data, intn_data_len, sign, 10, &unused_s_len);
430429
if (IS_NULL_PTR(s)) {
431430
return -1;
432431
}
@@ -1087,12 +1086,12 @@ avm_float_t term_conv_to_float(term t)
10871086
return term_unbox_int64(t);
10881087
#endif
10891088
default: {
1090-
const intn_digit_t *num = (intn_digit_t *) term_intn_data(t);
1091-
size_t digits_per_term = (sizeof(term) / sizeof(intn_digit_t));
1092-
size_t len = boxed_size * digits_per_term;
1093-
term_integer_sign_t t_sign = term_boxed_integer_sign(t);
1089+
const intn_digit_t *num;
1090+
size_t num_len;
1091+
intn_integer_sign_t num_sign;
1092+
term_to_bigint(t, &num, &num_len, &num_sign);
10941093

1095-
return intn_to_double(num, len, (intn_integer_sign_t) t_sign);
1094+
return intn_to_double(num, num_len, num_sign);
10961095
}
10971096
}
10981097
} else {

src/libAtomVM/term.h

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,12 +1315,6 @@ static inline void *term_intn_data(term t)
13151315
return (void *) (boxed_value + 1);
13161316
}
13171317

1318-
static inline size_t term_intn_size(term t)
1319-
{
1320-
const term *boxed_value = term_to_const_term_ptr(t);
1321-
return term_get_size_from_boxed_header(boxed_value[0]);
1322-
}
1323-
13241318
static inline void term_intn_to_term_size(size_t n, size_t *intn_data_size, size_t *rounded_num_len)
13251319
{
13261320
size_t bytes = n * sizeof(intn_digit_t);
@@ -1340,6 +1334,85 @@ static inline void term_intn_to_term_size(size_t n, size_t *intn_data_size, size
13401334
*rounded_num_len = rounded / sizeof(intn_digit_t);
13411335
}
13421336

1337+
/**
1338+
* @brief Check if term is a multi-precision integer larger than \c int64_t
1339+
*
1340+
* Tests whether a term represents a boxed integer that requires multi-precision
1341+
* representation (i.e., larger than can fit in \c int64_t). These are integers
1342+
* that need more than \c INTN_INT64_LEN digits for their representation.
1343+
*
1344+
* In the current implementation, a bigint is defined as a boxed integer with
1345+
* size greater than:
1346+
* - \c BOXED_TERMS_REQUIRED_FOR_INT64 on 32-bit systems
1347+
* - \c BOXED_TERMS_REQUIRED_FOR_INT on 64-bit systems
1348+
*
1349+
* This effectively identifies integers that cannot be represented in the
1350+
* platform's native integer types and require multi-precision arithmetic,
1351+
* while avoiding confusion with regular boxed \c int64_t values that still
1352+
* fit within standard integer ranges.
1353+
*
1354+
* @param t Term to check
1355+
* @return true if term is a multi-precision integer, false otherwise
1356+
*
1357+
* @note Returns false for integers that fit in \c int64_t, even if boxed
1358+
* @note This is the correct check before calling \c term_to_bigint()
1359+
*
1360+
* @see term_to_bigint() to extract the multi-precision integer data
1361+
* @see term_is_boxed_integer() for checking any boxed integer
1362+
* @see term_is_any_integer() for checking all integer representations
1363+
*/
1364+
static inline bool term_is_bigint(term t)
1365+
{
1366+
return term_is_boxed_integer(t)
1367+
&& (term_boxed_size(t) > (INTN_INT64_LEN * sizeof(intn_digit_t)) / sizeof(term));
1368+
}
1369+
1370+
// intn doesn't depend on term
1371+
_Static_assert(
1372+
(int) TermPositiveInteger == (int) IntNPositiveInteger, "term/intn definition mismatch");
1373+
_Static_assert(
1374+
(int) TermNegativeInteger == (int) IntNNegativeInteger, "term/intn definition mismatch");
1375+
1376+
/**
1377+
* @brief Extract multi-precision integer data from boxed term
1378+
*
1379+
* Extracts the raw multi-precision integer representation from a boxed
1380+
* integer term. This function provides direct access to the internal
1381+
* digit array without copying, returning a pointer to the data within
1382+
* the term structure.
1383+
*
1384+
* @param t Boxed integer term to extract from
1385+
* @param[out] bigint Pointer to the digit array within the term (borrowed reference)
1386+
* @param[out] bigint_len Number of digits in the integer
1387+
* @param[out] bigint_sign Sign of the integer
1388+
*
1389+
* @pre \c term_is_bigint(t) must be true
1390+
* @pre bigint != NULL
1391+
* @pre bigint_len != NULL
1392+
* @pre bigint_sign != NULL
1393+
*
1394+
* @warning Returned pointer is a borrowed reference into the term structure
1395+
* @warning Data becomes invalid if term is garbage collected or modified
1396+
* @warning Caller must not free the returned pointer
1397+
*
1398+
* @note The digit array may not be normalized (may have leading zeros)
1399+
* @note Length is calculated as boxed_size * (sizeof(term) / sizeof(intn_digit_t))
1400+
*
1401+
* @see term_is_bigint() to check if term is a multi-precision integer
1402+
* @see term_boxed_integer_sign() to get the sign
1403+
*/
1404+
static inline void term_to_bigint(
1405+
term t, const intn_digit_t *bigint[], size_t *bigint_len, intn_integer_sign_t *bigint_sign)
1406+
{
1407+
*bigint = (const intn_digit_t *) term_intn_data(t);
1408+
1409+
const term *boxed_value = term_to_const_term_ptr(t);
1410+
size_t boxed_size = term_get_size_from_boxed_header(boxed_value[0]);
1411+
*bigint_len = boxed_size * (sizeof(term) / sizeof(intn_digit_t));
1412+
1413+
*bigint_sign = (intn_integer_sign_t) term_boxed_integer_sign(t);
1414+
}
1415+
13431416
static inline term term_from_catch_label(unsigned int module_index, unsigned int label)
13441417
{
13451418
return (term) ((module_index << 24) | (label << 6) | TERM_IMMED2_CATCH);

0 commit comments

Comments
 (0)