Skip to content

Commit 6de1d25

Browse files
committed
Add support to bigint to erlang:binary_to_integer/1
Just use `intn_parse` function. Signed-off-by: Davide Bettio <davide@uninstall.it>
1 parent 4fd94d5 commit 6de1d25

File tree

2 files changed

+49
-5
lines changed

2 files changed

+49
-5
lines changed

src/libAtomVM/nifs.c

+34-3
Original file line numberDiff line numberDiff line change
@@ -1905,6 +1905,31 @@ static term nif_erlang_binary_to_atom_1(Context *ctx, int argc, term argv[])
19051905
return result;
19061906
}
19071907

1908+
static inline void intn_to_term_size(size_t n, size_t *intn_data_size, size_t *rounded_num_len)
1909+
{
1910+
size_t bytes = n * sizeof(intn_digit_t);
1911+
size_t rounded = ((bytes + 7) >> 3) << 3;
1912+
*intn_data_size = rounded / sizeof(term);
1913+
*rounded_num_len = rounded / sizeof(intn_digit_t);
1914+
}
1915+
1916+
static term make_bigint(Context *ctx, const intn_digit_t bigres[], size_t bigres_len)
1917+
{
1918+
size_t intn_data_size;
1919+
size_t rounded_res_len;
1920+
intn_to_term_size(bigres_len, &intn_data_size, &rounded_res_len);
1921+
1922+
if (UNLIKELY(memory_ensure_free(ctx, BOXED_INTN_SIZE(intn_data_size)) != MEMORY_GC_OK)) {
1923+
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
1924+
}
1925+
1926+
term bigres_term = term_create_uninitialized_intn(intn_data_size, &ctx->heap);
1927+
intn_digit_t *dest_buf = (void *) term_intn_data(bigres_term);
1928+
intn_sign_extend(bigres, bigres_len, rounded_res_len, dest_buf);
1929+
1930+
return bigres_term;
1931+
}
1932+
19081933
static term nif_erlang_binary_to_integer(Context *ctx, int argc, term argv[])
19091934
{
19101935
term bin_term = argv[0];
@@ -1926,11 +1951,17 @@ static term nif_erlang_binary_to_integer(Context *ctx, int argc, term argv[])
19261951
int bin_data_size = term_binary_size(bin_term);
19271952

19281953
int64_t value;
1929-
if (int64_parse_ascii_buf(bin_data, bin_data_size, base, BufToInt64NoOptions, &value) != bin_data_size) {
1954+
int parse_res
1955+
= int64_parse_ascii_buf(bin_data, bin_data_size, base, BufToInt64NoOptions, &value);
1956+
if (parse_res == bin_data_size) {
1957+
return make_maybe_boxed_int64(ctx, value);
1958+
} else if (parse_res > 0) {
1959+
intn_digit_t tmp_parsed[INTN_MAX_RES_LEN];
1960+
int parsed_digits = intn_parse(bin_data, bin_data_size, base, tmp_parsed);
1961+
return make_bigint(ctx, tmp_parsed, parsed_digits);
1962+
} else {
19301963
RAISE_ERROR(BADARG_ATOM);
19311964
}
1932-
1933-
return make_maybe_boxed_int64(ctx, value);
19341965
}
19351966

19361967
static bool is_valid_float_string(const char *str, int len)

tests/erlang_tests/bigint.erl

+15-2
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@
1919
%
2020

2121
-module(bigint).
22-
-export([start/0, mul/2, shrink/0, pow/2, twice/1, fact/1, get_machine_atom/0, expect_overflow/1]).
22+
-export([
23+
start/0, mul/2, shrink/0, pow/2, twice/1, fact/1, get_machine_atom/0, expect_overflow/1, id/1
24+
]).
2325

2426
start() ->
25-
test_mul().
27+
test_mul() +
28+
parse_bigint().
2629

2730
test_mul() ->
2831
Expected_INT64_MIN = ?MODULE:pow(-2, 63),
@@ -90,6 +93,16 @@ fact(N) when N rem 2 == 0 ->
9093
fact(N) when N rem 2 == 1 ->
9194
fact(N - 1) * N.
9295

96+
parse_bigint() ->
97+
PBI = erlang:binary_to_integer(?MODULE:id(<<"1234567892244667788990000000000000000025">>)),
98+
<<"1234567892244667788990000000000000000025">> = erlang:integer_to_binary(PBI),
99+
NBI = erlang:binary_to_integer(?MODULE:id(<<"-9234567892244667788990000000000000000025">>)),
100+
<<"-9234567892244667788990000000000000000025">> = erlang:integer_to_binary(NBI),
101+
0.
102+
103+
id(X) ->
104+
X.
105+
93106
expect_overflow(OvfFun) ->
94107
Machine = ?MODULE:get_machine_atom(),
95108
try {Machine, OvfFun()} of

0 commit comments

Comments
 (0)