Skip to content

Commit dfe2003

Browse files
committed
Add support for binary:copy/1,2
Signed-off-by: Paul Guyot <pguyot@kallisys.net>
1 parent 389ec97 commit dfe2003

File tree

6 files changed

+84
-0
lines changed

6 files changed

+84
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ also non string parameters (e.g. `Enum.join([1, 2], ",")`
2929
- Add support to Elixir for `Keyword.split/2`
3030
- Support for `binary:split/3` and `string:find/2,3`
3131
- Support for large tuples (more than 255 elements) in external terms.
32+
- Support for `binary:copy/1,2`
3233

3334
### Changed
3435

src/libAtomVM/nifs.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ static term binary_to_atom(Context *ctx, int argc, term argv[], int create_new);
8888
static term list_to_atom(Context *ctx, int argc, term argv[], int create_new);
8989

9090
static term nif_binary_at_2(Context *ctx, int argc, term argv[]);
91+
static term nif_binary_copy(Context *ctx, int argc, term argv[]);
9192
static term nif_binary_first_1(Context *ctx, int argc, term argv[]);
9293
static term nif_binary_last_1(Context *ctx, int argc, term argv[]);
9394
static term nif_binary_part_3(Context *ctx, int argc, term argv[]);
@@ -211,6 +212,12 @@ static const struct Nif binary_at_nif =
211212
.nif_ptr = nif_binary_at_2
212213
};
213214

215+
static const struct Nif binary_copy_nif =
216+
{
217+
.base.type = NIFFunctionType,
218+
.nif_ptr = nif_binary_copy
219+
};
220+
214221
static const struct Nif binary_first_nif =
215222
{
216223
.base.type = NIFFunctionType,
@@ -2943,6 +2950,37 @@ static term nif_binary_at_2(Context *ctx, int argc, term argv[])
29432950
return term_from_int11(term_binary_data(bin_term)[pos]);
29442951
}
29452952

2953+
static term nif_binary_copy(Context *ctx, int argc, term argv[])
2954+
{
2955+
term bin_term = argv[0];
2956+
VALIDATE_VALUE(bin_term, term_is_binary);
2957+
2958+
size_t count = 1;
2959+
2960+
if (argc == 2) {
2961+
term count_term = argv[1];
2962+
VALIDATE_VALUE(count_term, term_is_integer);
2963+
count = term_to_int(count_term);
2964+
}
2965+
2966+
size_t size = term_binary_size(bin_term);
2967+
size_t dest_size = size * count;
2968+
2969+
size_t alloc_heap_size = term_binary_heap_size(dest_size);
2970+
if (UNLIKELY(memory_ensure_free_with_roots(ctx, alloc_heap_size, 1, &bin_term, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
2971+
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
2972+
}
2973+
2974+
term result = term_create_uninitialized_binary(dest_size, &ctx->heap, ctx->global);
2975+
uint8_t *dest = (uint8_t *) term_binary_data(result);
2976+
const void *src = (const void *) term_binary_data(bin_term);
2977+
for (size_t i = 0; i < count; i++) {
2978+
memcpy((void *) dest, src, size);
2979+
dest += size;
2980+
}
2981+
return result;
2982+
}
2983+
29462984
static term nif_binary_first_1(Context *ctx, int argc, term argv[])
29472985
{
29482986
UNUSED(argc);

src/libAtomVM/nifs.gperf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ struct NifNameAndNifPtr
3232
};
3333
%%
3434
binary:at/2, &binary_at_nif
35+
binary:copy/1, &binary_copy_nif
36+
binary:copy/2, &binary_copy_nif
3537
binary:first/1, &binary_first_nif
3638
binary:last/1, &binary_last_nif
3739
binary:part/3, &binary_part_nif

tests/erlang_tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ compile_erlang(spawn_fun3)
267267
compile_erlang(binary_at_test)
268268
compile_erlang(binary_first_test)
269269
compile_erlang(binary_last_test)
270+
compile_erlang(test_binary_copy)
270271

271272
compile_erlang(test_integer_to_binary)
272273
compile_erlang(test_list_to_binary)
@@ -736,6 +737,7 @@ add_custom_target(erlang_test_modules DEPENDS
736737
binary_at_test.beam
737738
binary_first_test.beam
738739
binary_last_test.beam
740+
test_binary_copy.beam
739741

740742
test_integer_to_binary.beam
741743
test_list_to_binary.beam
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
%
2+
% This file is part of AtomVM.
3+
%
4+
% Copyright 2024 Paul Guyot <pguyot@kallisys.net>
5+
%
6+
% Licensed under the Apache License, Version 2.0 (the "License");
7+
% you may not use this file except in compliance with the License.
8+
% You may obtain a copy of the License at
9+
%
10+
% http://www.apache.org/licenses/LICENSE-2.0
11+
%
12+
% Unless required by applicable law or agreed to in writing, software
13+
% distributed under the License is distributed on an "AS IS" BASIS,
14+
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
% See the License for the specific language governing permissions and
16+
% limitations under the License.
17+
%
18+
% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
19+
%
20+
21+
-module(test_binary_copy).
22+
23+
-export([start/0]).
24+
25+
start() ->
26+
ok = test_copy1(),
27+
ok = test_copy2(),
28+
0.
29+
30+
test_copy1() ->
31+
<<>> = binary:copy(<<>>),
32+
<<"foo">> = binary:copy(<<"foo">>),
33+
ok.
34+
35+
test_copy2() ->
36+
<<>> = binary:copy(<<>>, 1),
37+
<<"foo">> = binary:copy(<<"foo">>, 1),
38+
<<>> = binary:copy(<<"foo">>, 0),
39+
<<"foofoo">> = binary:copy(<<"foo">>, 2),
40+
ok.

tests/test.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ struct Test tests[] = {
309309
TEST_CASE_EXPECTED(binary_at_test, 121),
310310
TEST_CASE_EXPECTED(binary_first_test, 82),
311311
TEST_CASE_EXPECTED(binary_last_test, 110),
312+
TEST_CASE(test_binary_copy),
312313

313314
TEST_CASE(test_integer_to_binary),
314315
TEST_CASE(test_list_to_binary),

0 commit comments

Comments
 (0)