Skip to content

Commit

Permalink
Add support for binary:copy/1,2
Browse files Browse the repository at this point in the history
Signed-off-by: Paul Guyot <[email protected]>
  • Loading branch information
pguyot committed Sep 29, 2024
1 parent 389ec97 commit dfe2003
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ also non string parameters (e.g. `Enum.join([1, 2], ",")`
- Add support to Elixir for `Keyword.split/2`
- Support for `binary:split/3` and `string:find/2,3`
- Support for large tuples (more than 255 elements) in external terms.
- Support for `binary:copy/1,2`

### Changed

Expand Down
38 changes: 38 additions & 0 deletions src/libAtomVM/nifs.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ static term binary_to_atom(Context *ctx, int argc, term argv[], int create_new);
static term list_to_atom(Context *ctx, int argc, term argv[], int create_new);

static term nif_binary_at_2(Context *ctx, int argc, term argv[]);
static term nif_binary_copy(Context *ctx, int argc, term argv[]);
static term nif_binary_first_1(Context *ctx, int argc, term argv[]);
static term nif_binary_last_1(Context *ctx, int argc, term argv[]);
static term nif_binary_part_3(Context *ctx, int argc, term argv[]);
Expand Down Expand Up @@ -211,6 +212,12 @@ static const struct Nif binary_at_nif =
.nif_ptr = nif_binary_at_2
};

static const struct Nif binary_copy_nif =
{
.base.type = NIFFunctionType,
.nif_ptr = nif_binary_copy
};

static const struct Nif binary_first_nif =
{
.base.type = NIFFunctionType,
Expand Down Expand Up @@ -2943,6 +2950,37 @@ static term nif_binary_at_2(Context *ctx, int argc, term argv[])
return term_from_int11(term_binary_data(bin_term)[pos]);
}

static term nif_binary_copy(Context *ctx, int argc, term argv[])
{
term bin_term = argv[0];
VALIDATE_VALUE(bin_term, term_is_binary);

size_t count = 1;

if (argc == 2) {
term count_term = argv[1];
VALIDATE_VALUE(count_term, term_is_integer);
count = term_to_int(count_term);
}

size_t size = term_binary_size(bin_term);
size_t dest_size = size * count;

size_t alloc_heap_size = term_binary_heap_size(dest_size);
if (UNLIKELY(memory_ensure_free_with_roots(ctx, alloc_heap_size, 1, &bin_term, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
}

term result = term_create_uninitialized_binary(dest_size, &ctx->heap, ctx->global);
uint8_t *dest = (uint8_t *) term_binary_data(result);
const void *src = (const void *) term_binary_data(bin_term);
for (size_t i = 0; i < count; i++) {
memcpy((void *) dest, src, size);
dest += size;
}
return result;
}

static term nif_binary_first_1(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
Expand Down
2 changes: 2 additions & 0 deletions src/libAtomVM/nifs.gperf
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ struct NifNameAndNifPtr
};
%%
binary:at/2, &binary_at_nif
binary:copy/1, &binary_copy_nif
binary:copy/2, &binary_copy_nif
binary:first/1, &binary_first_nif
binary:last/1, &binary_last_nif
binary:part/3, &binary_part_nif
Expand Down
2 changes: 2 additions & 0 deletions tests/erlang_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ compile_erlang(spawn_fun3)
compile_erlang(binary_at_test)
compile_erlang(binary_first_test)
compile_erlang(binary_last_test)
compile_erlang(test_binary_copy)

compile_erlang(test_integer_to_binary)
compile_erlang(test_list_to_binary)
Expand Down Expand Up @@ -736,6 +737,7 @@ add_custom_target(erlang_test_modules DEPENDS
binary_at_test.beam
binary_first_test.beam
binary_last_test.beam
test_binary_copy.beam

test_integer_to_binary.beam
test_list_to_binary.beam
Expand Down
40 changes: 40 additions & 0 deletions tests/erlang_tests/test_binary_copy.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
%
% This file is part of AtomVM.
%
% Copyright 2024 Paul Guyot <[email protected]>
%
% Licensed under the Apache License, Version 2.0 (the "License");
% you may not use this file except in compliance with the License.
% You may obtain a copy of the License at
%
% http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS,
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing permissions and
% limitations under the License.
%
% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
%

-module(test_binary_copy).

-export([start/0]).

start() ->
ok = test_copy1(),
ok = test_copy2(),
0.

test_copy1() ->
<<>> = binary:copy(<<>>),
<<"foo">> = binary:copy(<<"foo">>),
ok.

test_copy2() ->
<<>> = binary:copy(<<>>, 1),
<<"foo">> = binary:copy(<<"foo">>, 1),
<<>> = binary:copy(<<"foo">>, 0),
<<"foofoo">> = binary:copy(<<"foo">>, 2),
ok.
1 change: 1 addition & 0 deletions tests/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ struct Test tests[] = {
TEST_CASE_EXPECTED(binary_at_test, 121),
TEST_CASE_EXPECTED(binary_first_test, 82),
TEST_CASE_EXPECTED(binary_last_test, 110),
TEST_CASE(test_binary_copy),

TEST_CASE(test_integer_to_binary),
TEST_CASE(test_list_to_binary),
Expand Down

0 comments on commit dfe2003

Please sign in to comment.