Skip to content

Commit

Permalink
Merge pull request #687 from fadushin/interop-iolist-additions
Browse files Browse the repository at this point in the history
Added interop_iolist_fold

This PR adds a function that supports traversal of values (integers and
binaries) in an IO list.

These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).

SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
  • Loading branch information
bettio committed Aug 8, 2023
2 parents adeba7b + a15c922 commit 6dd47da
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 55 deletions.
93 changes: 38 additions & 55 deletions src/libAtomVM/interop.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,19 +176,16 @@ term interop_proplist_get_value_default(term list, term key, term default_value)
return default_value;
}

InteropFunctionResult interop_iolist_size(term t, size_t *size)
inline InteropFunctionResult interop_iolist_fold(term t, interop_iolist_fold_fun fold_fun, void *accum)
{
if (term_is_binary(t)) {
*size = term_binary_size(t);
return InteropOk;
return fold_fun(t, accum);
}

if (UNLIKELY(!term_is_list(t))) {
return InteropBadArg;
}

unsigned long acc = 0;

struct TempStack temp_stack;
if (UNLIKELY(temp_stack_init(&temp_stack) != TempStackOk)) {
return InteropMemoryAllocFail;
Expand All @@ -200,9 +197,14 @@ InteropFunctionResult interop_iolist_size(term t, size_t *size)
}

while (!temp_stack_is_empty(&temp_stack)) {
if (term_is_integer(t)) {
acc++;
t = temp_stack_pop(&temp_stack);
if (term_is_integer(t) || term_is_binary(t)) {
InteropFunctionResult result = fold_fun(t, accum);
if (UNLIKELY(result != InteropOk)) {
temp_stack_destroy(&temp_stack);
return result;
} else {
t = temp_stack_pop(&temp_stack);
}

} else if (term_is_nil(t)) {
t = temp_stack_pop(&temp_stack);
Expand All @@ -214,10 +216,6 @@ InteropFunctionResult interop_iolist_size(term t, size_t *size)
}
t = term_get_list_head(t);

} else if (term_is_binary(t)) {
acc += term_binary_size(t);
t = temp_stack_pop(&temp_stack);

} else {
temp_stack_destroy(&temp_stack);
return InteropBadArg;
Expand All @@ -226,60 +224,45 @@ InteropFunctionResult interop_iolist_size(term t, size_t *size)

temp_stack_destroy(&temp_stack);

*size = acc;
return InteropOk;
}

InteropFunctionResult interop_write_iolist(term t, char *p)
static inline InteropFunctionResult size_fold_fun(term t, void *accum)
{
if (term_is_binary(t)) {
int len = term_binary_size(t);
memcpy(p, term_binary_data(t), len);
return InteropOk;
}

struct TempStack temp_stack;
if (UNLIKELY(temp_stack_init(&temp_stack) != TempStackOk)) {
return InteropMemoryAllocFail;
}

if (UNLIKELY(temp_stack_push(&temp_stack, t) != TempStackOk)) {
temp_stack_destroy(&temp_stack);
return InteropMemoryAllocFail;
size_t *size = (size_t *) accum;
if (term_is_integer(t)) {
*size += 1;
} else if (term_is_binary(t)) {
*size += term_binary_size(t);
}
return InteropOk;
}

while (!temp_stack_is_empty(&temp_stack)) {
if (term_is_integer(t)) {
*p = term_to_int(t);
p++;
t = temp_stack_pop(&temp_stack);

} else if (term_is_nil(t)) {
t = temp_stack_pop(&temp_stack);

} else if (term_is_nonempty_list(t)) {
if (UNLIKELY(temp_stack_push(&temp_stack, term_get_list_tail(t)) != TempStackOk)) {
temp_stack_destroy(&temp_stack);
return InteropMemoryAllocFail;
}
t = term_get_list_head(t);

} else if (term_is_binary(t)) {
int len = term_binary_size(t);
memcpy(p, term_binary_data(t), len);
p += len;
t = temp_stack_pop(&temp_stack);
InteropFunctionResult interop_iolist_size(term t, size_t *size)
{
*size = 0;
return interop_iolist_fold(t, size_fold_fun, size);
}

} else {
temp_stack_destroy(&temp_stack);
return InteropBadArg;
}
static inline InteropFunctionResult write_string_fold_fun(term t, void *accum)
{
char **p = (char **) accum;
if (term_is_integer(t)) {
**p = term_to_int(t);
(*p)++;
} else if (term_is_binary(t)) {
int len = term_binary_size(t);
memcpy(*p, term_binary_data(t), len);
*p += len;
}

temp_stack_destroy(&temp_stack);
return InteropOk;
}

InteropFunctionResult interop_write_iolist(term t, char *p)
{
return interop_iolist_fold(t, write_string_fold_fun, (void *) &p);
}

term interop_map_get_value(GlobalContext *glb, term map, term key)
{
return interop_map_get_value_default(glb, map, key, term_nil());
Expand Down
3 changes: 3 additions & 0 deletions src/libAtomVM/interop.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ typedef struct
int i_val;
} AtomStringIntPair;

typedef InteropFunctionResult (*interop_iolist_fold_fun)(term t, void *accum);

char *interop_term_to_string(term t, int *ok);
char *interop_binary_to_string(term binary);
char *interop_list_to_string(term list, int *ok);
Expand All @@ -65,6 +67,7 @@ term interop_map_get_value_default(GlobalContext *glb, term map, term key, term

NO_DISCARD InteropFunctionResult interop_iolist_size(term t, size_t *size);
NO_DISCARD InteropFunctionResult interop_write_iolist(term t, char *p);
NO_DISCARD InteropFunctionResult interop_iolist_fold(term t, interop_iolist_fold_fun fold_fun, void *accum);

/**
* @brief Finds on a table the first matching atom string.
Expand Down

0 comments on commit 6dd47da

Please sign in to comment.