Skip to content

Commit 6dd47da

Browse files
committed
Merge pull request #687 from fadushin/interop-iolist-additions
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
2 parents adeba7b + a15c922 commit 6dd47da

File tree

2 files changed

+41
-55
lines changed

2 files changed

+41
-55
lines changed

src/libAtomVM/interop.c

Lines changed: 38 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -176,19 +176,16 @@ term interop_proplist_get_value_default(term list, term key, term default_value)
176176
return default_value;
177177
}
178178

179-
InteropFunctionResult interop_iolist_size(term t, size_t *size)
179+
inline InteropFunctionResult interop_iolist_fold(term t, interop_iolist_fold_fun fold_fun, void *accum)
180180
{
181181
if (term_is_binary(t)) {
182-
*size = term_binary_size(t);
183-
return InteropOk;
182+
return fold_fun(t, accum);
184183
}
185184

186185
if (UNLIKELY(!term_is_list(t))) {
187186
return InteropBadArg;
188187
}
189188

190-
unsigned long acc = 0;
191-
192189
struct TempStack temp_stack;
193190
if (UNLIKELY(temp_stack_init(&temp_stack) != TempStackOk)) {
194191
return InteropMemoryAllocFail;
@@ -200,9 +197,14 @@ InteropFunctionResult interop_iolist_size(term t, size_t *size)
200197
}
201198

202199
while (!temp_stack_is_empty(&temp_stack)) {
203-
if (term_is_integer(t)) {
204-
acc++;
205-
t = temp_stack_pop(&temp_stack);
200+
if (term_is_integer(t) || term_is_binary(t)) {
201+
InteropFunctionResult result = fold_fun(t, accum);
202+
if (UNLIKELY(result != InteropOk)) {
203+
temp_stack_destroy(&temp_stack);
204+
return result;
205+
} else {
206+
t = temp_stack_pop(&temp_stack);
207+
}
206208

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

217-
} else if (term_is_binary(t)) {
218-
acc += term_binary_size(t);
219-
t = temp_stack_pop(&temp_stack);
220-
221219
} else {
222220
temp_stack_destroy(&temp_stack);
223221
return InteropBadArg;
@@ -226,60 +224,45 @@ InteropFunctionResult interop_iolist_size(term t, size_t *size)
226224

227225
temp_stack_destroy(&temp_stack);
228226

229-
*size = acc;
230227
return InteropOk;
231228
}
232229

233-
InteropFunctionResult interop_write_iolist(term t, char *p)
230+
static inline InteropFunctionResult size_fold_fun(term t, void *accum)
234231
{
235-
if (term_is_binary(t)) {
236-
int len = term_binary_size(t);
237-
memcpy(p, term_binary_data(t), len);
238-
return InteropOk;
239-
}
240-
241-
struct TempStack temp_stack;
242-
if (UNLIKELY(temp_stack_init(&temp_stack) != TempStackOk)) {
243-
return InteropMemoryAllocFail;
244-
}
245-
246-
if (UNLIKELY(temp_stack_push(&temp_stack, t) != TempStackOk)) {
247-
temp_stack_destroy(&temp_stack);
248-
return InteropMemoryAllocFail;
232+
size_t *size = (size_t *) accum;
233+
if (term_is_integer(t)) {
234+
*size += 1;
235+
} else if (term_is_binary(t)) {
236+
*size += term_binary_size(t);
249237
}
238+
return InteropOk;
239+
}
250240

251-
while (!temp_stack_is_empty(&temp_stack)) {
252-
if (term_is_integer(t)) {
253-
*p = term_to_int(t);
254-
p++;
255-
t = temp_stack_pop(&temp_stack);
256-
257-
} else if (term_is_nil(t)) {
258-
t = temp_stack_pop(&temp_stack);
259-
260-
} else if (term_is_nonempty_list(t)) {
261-
if (UNLIKELY(temp_stack_push(&temp_stack, term_get_list_tail(t)) != TempStackOk)) {
262-
temp_stack_destroy(&temp_stack);
263-
return InteropMemoryAllocFail;
264-
}
265-
t = term_get_list_head(t);
266-
267-
} else if (term_is_binary(t)) {
268-
int len = term_binary_size(t);
269-
memcpy(p, term_binary_data(t), len);
270-
p += len;
271-
t = temp_stack_pop(&temp_stack);
241+
InteropFunctionResult interop_iolist_size(term t, size_t *size)
242+
{
243+
*size = 0;
244+
return interop_iolist_fold(t, size_fold_fun, size);
245+
}
272246

273-
} else {
274-
temp_stack_destroy(&temp_stack);
275-
return InteropBadArg;
276-
}
247+
static inline InteropFunctionResult write_string_fold_fun(term t, void *accum)
248+
{
249+
char **p = (char **) accum;
250+
if (term_is_integer(t)) {
251+
**p = term_to_int(t);
252+
(*p)++;
253+
} else if (term_is_binary(t)) {
254+
int len = term_binary_size(t);
255+
memcpy(*p, term_binary_data(t), len);
256+
*p += len;
277257
}
278-
279-
temp_stack_destroy(&temp_stack);
280258
return InteropOk;
281259
}
282260

261+
InteropFunctionResult interop_write_iolist(term t, char *p)
262+
{
263+
return interop_iolist_fold(t, write_string_fold_fun, (void *) &p);
264+
}
265+
283266
term interop_map_get_value(GlobalContext *glb, term map, term key)
284267
{
285268
return interop_map_get_value_default(glb, map, key, term_nil());

src/libAtomVM/interop.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ typedef struct
5353
int i_val;
5454
} AtomStringIntPair;
5555

56+
typedef InteropFunctionResult (*interop_iolist_fold_fun)(term t, void *accum);
57+
5658
char *interop_term_to_string(term t, int *ok);
5759
char *interop_binary_to_string(term binary);
5860
char *interop_list_to_string(term list, int *ok);
@@ -65,6 +67,7 @@ term interop_map_get_value_default(GlobalContext *glb, term map, term key, term
6567

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

6972
/**
7073
* @brief Finds on a table the first matching atom string.

0 commit comments

Comments
 (0)