Skip to content

Commit

Permalink
Add ByteArray.resize and apply in ByteArray.filled
Browse files Browse the repository at this point in the history
This adds ByteArray.resize, used to efficiently resize a ByteArray and
fill it with new values (or truncate it). This method is then used in
ByteArray.filled to reduce the overhead of creating a ByteArray filled
with certain values.

Changelog: added
  • Loading branch information
yorickpeterse committed Oct 16, 2022
1 parent 91033b4 commit a169a55
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 8 deletions.
3 changes: 3 additions & 0 deletions bytecode/src/lib.rs
Expand Up @@ -909,6 +909,7 @@ pub enum BuiltinFunction {
ByteArraySlice,
ByteArrayAppend,
ByteArrayCopyFrom,
ByteArrayResize,
}

impl BuiltinFunction {
Expand Down Expand Up @@ -1064,6 +1065,7 @@ impl BuiltinFunction {
BuiltinFunction::ByteArraySlice => 147,
BuiltinFunction::ByteArrayAppend => 148,
BuiltinFunction::ByteArrayCopyFrom => 149,
BuiltinFunction::ByteArrayResize => 150,
}
}

Expand Down Expand Up @@ -1261,6 +1263,7 @@ impl BuiltinFunction {
BuiltinFunction::ByteArraySlice => "byte_array_slice",
BuiltinFunction::ByteArrayAppend => "byte_array_append",
BuiltinFunction::ByteArrayCopyFrom => "byte_array_copy_from",
BuiltinFunction::ByteArrayResize => "byte_array_resize",
}
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/src/type_check/methods.rs
Expand Up @@ -1446,6 +1446,7 @@ pub(crate) fn define_builtin_functions(state: &mut State) -> bool {
(BIF::ByteArraySlice, byte_array, never),
(BIF::ByteArrayAppend, nil, never),
(BIF::ByteArrayCopyFrom, int, never),
(BIF::ByteArrayResize, nil, never),
];

// Regular VM instructions exposed directly to the standard library. These
Expand Down
33 changes: 26 additions & 7 deletions libstd/src/std/byte_array.inko
Expand Up @@ -56,14 +56,8 @@ class builtin ByteArray {
# bytes[1] # => 0
fn pub static filled(with: Int, times: Int) -> ByteArray {
let bytes = new
let mut index = 0

while index < times {
bytes.push(with)

index += 1
}

bytes.resize(times, with)
bytes
}

Expand Down Expand Up @@ -295,6 +289,31 @@ class builtin ByteArray {
fn pub mut copy_from(bytes: ref ByteArray, at: Int, length: Int) -> Int {
_INKO.byte_array_copy_from(self, bytes, at, length)
}

# Resizes `self` to the new length.
#
# If the given length is greater than the current length, the `value` argument
# is used to fill in the additional slots. If the given length is less than
# the current length, `self` is simply truncated.
#
# # Panics
#
# This method panics if the given length is less than zero.
#
# # Examples
#
# let bytes = ByteArray.new
#
# bytes.resize(length: 2, value: 1)
# bytes # => ByteArray.from_array([1, 1])
#
# bytes.resize(length: 0, value: 0)
# bytes # => ByteArray.new
fn pub mut resize(length: Int, value: Int) {
if length < 0 { panic('The new length must be greater than zero') }

_INKO.byte_array_resize(self, length, value)
}
}

impl Drop for ByteArray {
Expand Down
19 changes: 18 additions & 1 deletion libstd/test/std/test_byte_array.inko
@@ -1,4 +1,4 @@
import helpers::(fmt, hash)
import helpers::(fmt, hash, Script)
import std::iter::EOF
import std::test::Tests

Expand Down Expand Up @@ -246,4 +246,21 @@ fn pub tests(t: mut Tests) {
t.equal(b.copy_from(b, at: 0, length: 2), 2)
t.equal(b, ByteArray.from_array([1, 2, 1, 2]))
}

t.test('ByteArray.resize') fn (t) {
let bytes = ByteArray.new

bytes.resize(length: 2, value: 1)
t.equal(bytes, ByteArray.from_array([1, 1]))

bytes.resize(length: 0, value: 0)
t.equal(bytes, ByteArray.new)

t.true(
Script
.new(id: t.id, code: 'ByteArray.new.resize(length: -5, value: 0)')
.run
.contains?('greater than zero')
)
}
}
1 change: 1 addition & 0 deletions vm/src/builtin_functions.rs
Expand Up @@ -205,6 +205,7 @@ impl BuiltinFunctions {
byte_array::byte_array_slice,
byte_array::byte_array_append,
byte_array::byte_array_copy_from,
byte_array::byte_array_resize,
],
}
}
Expand Down
14 changes: 14 additions & 0 deletions vm/src/builtin_functions/byte_array.rs
Expand Up @@ -85,3 +85,17 @@ pub(crate) fn byte_array_copy_from(
target.value_mut().extend_from_slice(slice);
Ok(Int::alloc(state.permanent_space.int_class(), amount))
}

pub(crate) fn byte_array_resize(
_: &State,
_: &mut Thread,
_: ProcessPointer,
args: &[Pointer],
) -> Result<Pointer, RuntimeError> {
let bytes = unsafe { args[0].get_mut::<ByteArray>() };
let size = unsafe { Int::read(args[1]) as usize };
let filler = unsafe { Int::read(args[2]) as u8 };

bytes.value_mut().resize(size, filler);
Ok(Pointer::nil_singleton())
}

0 comments on commit a169a55

Please sign in to comment.