Skip to content

Commit 2766c05

Browse files
committed
intn: add intn_from_integer_bytes function
This function converts n-bytes in either big or little endian format, signed / unsigned, and converts them into a intn integer. Signed-off-by: Davide Bettio <davide@uninstall.it>
1 parent f916c11 commit 2766c05

File tree

2 files changed

+85
-0
lines changed

2 files changed

+85
-0
lines changed

src/libAtomVM/intn.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,3 +622,75 @@ int intn_parse(
622622
// let's count at the end
623623
return out_len;
624624
}
625+
626+
static size_t cond_neg_in_place(intn_integer_sign_t sign, intn_digit_t out[])
627+
{
628+
if (sign == IntNNegativeInteger) {
629+
uint32_t carry = 1;
630+
size_t i;
631+
int last_non_zero = -1;
632+
for (i = 0; i < INTN_MAX_RES_LEN - 1; i++) {
633+
uint64_t temp = (uint64_t) (~out[i]) + (uint64_t) carry;
634+
if ((uint32_t) temp != 0) {
635+
last_non_zero = i;
636+
}
637+
out[i] = (uint32_t) temp;
638+
carry = temp >> 32;
639+
}
640+
if (carry) {
641+
out[i] = carry;
642+
return i;
643+
} else {
644+
return last_non_zero + 1;
645+
}
646+
} else {
647+
return intn_count_digits(out, INTN_MAX_IN_LEN);
648+
}
649+
}
650+
651+
int intn_from_integer_bytes(const uint8_t in[], size_t in_size, intn_from_integer_options_t opts,
652+
intn_digit_t out[], intn_integer_sign_t *out_sign)
653+
{
654+
size_t msb_index;
655+
if (opts & IntnLittleEndian) {
656+
msb_index = in_size - 1;
657+
} else {
658+
msb_index = 0;
659+
}
660+
661+
uint8_t filler = 0x00;
662+
intn_integer_sign_t sign = IntNPositiveInteger;
663+
if (opts & IntnSigned) {
664+
if (in[msb_index] & 0x80) {
665+
filler = 0xFF;
666+
sign = IntNNegativeInteger;
667+
}
668+
*out_sign = sign;
669+
}
670+
671+
memset(out, filler, INTN_MAX_RES_LEN * sizeof(intn_digit_t));
672+
673+
size_t dest_j = in_size;
674+
675+
if (UNLIKELY(dest_j / sizeof(intn_digit_t) >= INTN_MAX_RES_LEN)) {
676+
return -1;
677+
}
678+
679+
if (opts & IntnLittleEndian) {
680+
for (int i = in_size - 1; i >= 0; i--) {
681+
dest_j--;
682+
size_t dest_block = dest_j / sizeof(intn_digit_t);
683+
out[dest_block] <<= 8;
684+
out[dest_block] |= in[i];
685+
}
686+
} else {
687+
for (size_t i = 0; i < in_size; i++) {
688+
dest_j--;
689+
size_t dest_block = dest_j / sizeof(intn_digit_t);
690+
out[dest_block] <<= 8;
691+
out[dest_block] |= in[i];
692+
}
693+
}
694+
695+
return cond_neg_in_place(sign, out);
696+
}

src/libAtomVM/intn.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,22 @@
4646
#define INTN_DIV_OUT_LEN(m, n) ((m) - (n) + 1 + 1)
4747
#define INTN_ABS_OUT_LEN(m) ((m) + 1)
4848

49+
#define INTN_MAX_UNSIGNED_BYTES_SIZE 32
50+
#define INTN_MAX_UNSIGNED_BITS_SIZE 256
51+
4952
typedef enum
5053
{
5154
IntNPositiveInteger = 0,
5255
IntNNegativeInteger = 4
5356
} intn_integer_sign_t;
5457

58+
typedef enum
59+
{
60+
IntnUnsignedBigEndian = 0,
61+
IntnSigned = 1,
62+
IntnLittleEndian = 2
63+
} intn_from_integer_options_t;
64+
5565
typedef uint32_t intn_digit_t;
5666

5767
size_t intn_addmnu(
@@ -73,6 +83,9 @@ int intn_parse(
7383
double intn_to_double(const intn_digit_t *num, size_t len, intn_integer_sign_t sign);
7484
int intn_from_double(double dnum, intn_digit_t *out, intn_integer_sign_t *out_sign);
7585

86+
int intn_from_integer_bytes(const uint8_t in[], size_t in_size, intn_from_integer_options_t opts,
87+
intn_digit_t out[], intn_integer_sign_t *out_sign);
88+
7689
static inline void intn_copy(
7790
const intn_digit_t *num, size_t num_len, intn_digit_t *out, size_t extend_to)
7891
{

0 commit comments

Comments
 (0)