std.bytes.ByteArray
type pub ByteArray
An array of bytes.
Byte arrays are arrays specialised for storing individual bytes in the most
efficient way possible. Unlike a regular Array
of Int
values, each value
only requires a single byte of space, instead of requiring 8 bytes of space.
Byte arrays are primarily meant for reading and writing data from/to a stream,
such as a file or a socket. If you simply want to store a list of numbers,
you're better off using the Array
type.
Static methods
filled
Show source codeHide source code
fn pub static filled(with: Int, times: Int) -> ByteArray {
let bytes = with_capacity(times)
alloc.write(byte: with, to: bytes.buffer, size: times)
bytes.size = times
bytes
}
fn pub static filled(with: Int, times: Int) -> ByteArray
Returns a ByteArray
filled with the given byte.
The times
argument specifies how many times the with
argument must
exist in the byte array.
Panics
This method panics of times
if less than zero.
Examples
let bytes = ByteArray.filled(with: 0, times: 2)
bytes.get(0) # => 0
bytes.get(1) # => 0
from_array
Show source codeHide source code
fn pub static from_array(array: ref Array[Int]) -> ByteArray {
let bytes = ByteArray.with_capacity(array.size)
for v in array.iter { bytes.push(v) }
bytes
}
fn pub static from_array(array: ref Array[Int]) -> ByteArray
Returns a new ByteArray
created from the given Array
.
from_pointer
Show source codeHide source code
fn pub static from_pointer(pointer: Pointer[UInt8], size: Int) -> ByteArray {
if size < 0 { invalid_size(size) }
# While it's unlikely for `pointer` to be NULL while `size` is e.g. 4, it
# doesn't hurt to check as the alternative is a hard crash.
if pointer as Int == 0 { return new }
let bytes = with_capacity(size)
alloc.copy(pointer, bytes.buffer, size)
bytes.size = size
bytes
}
fn pub static from_pointer(pointer: Pointer[UInt8], size: Int) -> ByteArray
Returns a ByteArray
created from a raw pointer.
The size
argument specifies the number of bytes to read starting at the
given pointer.
If size
is greater than zero but pointer
is NULL, the returned value is
an empty ByteArray
.
Safety
If size
is greater than zero and pointer
points to invalid memory (but
isn't NULL), the behavior is undefined and will likely result in a crash.
The purpose of this method is to allow creating a ByteArray
from a pointer
returned by C code. Avoid using this method for anything else.
Panics
This method panics of size
if less than zero.
new
Show source codeHide source code
fn pub static new -> ByteArray {
Self(size: 0, capacity: 0, buffer: 0 as Pointer[UInt8])
}
fn pub static new -> ByteArray
Returns a new empty ByteArray
.
Examples
let bytes = ByteArray.new
bytes.size # => 0
bytes.capacity # => 0
with_capacity
Show source codeHide source code
fn pub static with_capacity(size: Int) -> ByteArray {
if size < 0 { invalid_capacity(size) }
Self(
size: 0,
capacity: size,
buffer: alloc.resize(0 as Pointer[UInt8], size),
)
}
fn pub static with_capacity(size: Int) -> ByteArray
Returns a ByteArray
with enough space for at least size
bytes.
Panics
This method panics of size
if less than zero.
Examples
ByteArray.with_capacity(32).capacity # => 32
Instance methods
!=
Show source codeHide source code
fn pub !=(other: ref Self) -> Bool {
(self == other).false?
}
fn pub !=(other: ref Self) -> Bool
Returns true
if self
and the given object are not equal to each other.
==
Show source codeHide source code
fn pub ==(other: ref ByteArray) -> Bool {
let size = self.size
if size == other.size {
ptr.equal(pointer, other.pointer, size: size)
} else {
false
}
}
fn pub ==(other: ref ByteArray) -> Bool
Returns true
if two ByteArray
objects are equal to each other.
Two ByteArray
objects are considered equal if they have the exact same
values in the exact same order.
Examples
Comparing two ByteArray
objects:
ByteArray.from_array([10]) == ByteArray.from_array([10]) # => true
ByteArray.from_array([10]) == ByteArray.from_array([20]) # => false
append
Show source codeHide source code
fn pub mut append[T: Bytes](bytes: ref T) {
let len = bytes.size
if len == 0 { return }
reserve_exact(len)
alloc.copy(from: bytes.pointer, to: tail, size: len)
@size += len
}
fn pub mut append[T: Bytes](bytes: ref T)
Copies the bytes from bytes
to the end of self
.
The bytes
argument can be any type that implements the Bytes
trait, such
as String
, ByteArray
, or Slice
.
Examples
let a = ByteArray.from_array([1, 2, 3, 4])
let b = ByteArray.new
let c = ByteArray.new
b.append(a)
c.append(a.slice(start: 0, end: 2))
b # => ByteArray.from_array([1, 2, 3, 4])
c # => ByteArray.from_array([1, 2])
bytes
Show source codeHide source code
fn pub bytes -> Iter[ref Self] {
Iter(source: self, index: 0)
}
fn pub bytes -> Iter[ref Self]
Returns an iterator over the bytes in self
.
Examples
let bytes = ByteArray.from_array([10, 20, 30])
let iter = bytes.bytes
iter.next # => Option.Some(10)
capacity
Show source codeHide source code
fn pub inline capacity -> Int {
@capacity
}
fn pub inline capacity -> Int
Returns the number of bytes that can be stored in self
before self
needs
to be resized.
Examples
ByteArray.new.capacity # => 0
ByteArray.with_capacity(32).capacity # => 32
clear
Show source codeHide source code
fn pub mut clear {
@size = 0
}
fn pub mut clear
Removes all values from this ByteArray
.
This method has no effect on the amount of memory reserved by self
,
instead it merely sets the size of self
to zero.
Examples
Removing all values:
let bytes = ByteArray.from_array([10, 20, 30])
bytes.clear
bytes.size # => 0
clone
Show source codeHide source code
fn pub clone -> ByteArray {
let new = ByteArray.new
let _ = new.append(self)
new
}
fn pub clone -> ByteArray
Creates a clone of self
.
The returned value is an owned value that is the same type as the receiver
of this method. For example, cloning a ref Array[Int]
results in a
Array[Int]
, not another ref Array[Int]
.
contains?
Show source codeHide source code
fn pub contains?(value: Int) -> Bool {
iter.any?(fn (ours) { ours == value })
}
fn pub contains?(value: Int) -> Bool
Returns true
if the given byte is contained in self
.
Examples
let bytes = ByteArray.from_array([10, 20])
bytes.contains?(10) # => true
contains_bytes?
Show source codeHide source code
fn pub contains_bytes?[B: Bytes](bytes: ref B) -> Bool {
index_of(bytes, starting_at: 0).some?
}
fn pub contains_bytes?[B: Bytes](bytes: ref B) -> Bool
Returns true
if self
contains the given byte sequence.
Examples
'hello'.contains_bytes?('hello') # => true
drain_to_string
Show source codeHide source code
fn pub mut drain_to_string -> String {
if empty? { return '' }
let str = String.from_primitive(inko_string_from_bytes(@buffer, @size))
clear
str
}
fn pub mut drain_to_string -> String
Returns a new String
using the bytes in this ByteArray
, draining it in
the process.
After this method is finished, self
is empty.
Examples
let bytes = ByteArray.from_array([105, 110, 107, 111])
bytes.drain_to_string # => 'inko'
bytes.empty? # => true
empty?
Show source codeHide source code
fn pub inline empty? -> Bool {
@size == 0
}
fn pub inline empty? -> Bool
Returns true
if self
is empty.
Examples
ByteArray.new.empty? => true
ends_with?
Show source codeHide source code
fn pub ends_with?[T: Bytes](suffix: ref T) -> Bool {
ptr.ends_with?(@buffer, size, suffix.pointer, suffix.size)
}
fn pub ends_with?[T: Bytes](suffix: ref T) -> Bool
Returns true
if self
ends with the given sequence of bytes.
Examples
'hello'.to_byte_array.ends_with?('o'.to_byte_array) # => true
'hello'.to_byte_array.ends_with?('o') # => true
equals?
Show source codeHide source code
fn pub equals?[O: Bytes](other: ref O) -> Bool {
let len = size
len == other.size and (len == 0 or ptr.equal(pointer, other.pointer, len))
}
fn pub equals?[O: Bytes](other: ref O) -> Bool
Returns true
if self
and other
contain identical bytes.
This allows comparing of any Bytes
type with any other Bytes
type (e.g.
comparing a String
to a ByteArray
). In contrast, methods such as
String.==
only support comparing against values of the same type.
Examples
'hello'.equals?('hello') # => true
'hello'.equals?('hello'.to_byte_array) # => true
fmt
Show source codeHide source code
fn pub fmt(formatter: mut Formatter) {
let fmt = formatter.array
for byte in iter { fmt.value(byte) }
fmt.finish
}
fn pub fmt(formatter: mut Formatter)
Formats self
in a human-readable format for debugging purposes.
get
Show source codeHide source code
fn pub inline get(index: Int) -> Result[Int, OutOfBounds] {
try check_bounds(index, size)
Result.Ok(get_unchecked(index))
}
fn pub inline get(index: Int) -> Result[Int, OutOfBounds]
Returns the byte at the given index.
If the index is out of bounds, a std.bounds.OutOfBounds
error is returned.
Examples
let bytes = ByteArray.from_array([10, 20])
bytes.get(0) # => Result.Ok(10)
bytes.get(5) # => Result.Error(OutOfBounds(...))
hash
Show source codeHide source code
fn pub hash[H: mut + Hasher](hasher: mut H) {
hash_bytes(self, hasher)
}
fn pub hash[H: mut + Hasher](hasher: mut H: mut)
Writes the hash for self
into the given Hasher
.
index_of
Show source codeHide source code
fn pub index_of[B: Bytes](value: ref B, starting_at: Int) -> Option[Int] {
# This is a naive string searching algorithm (see
# https://en.wikipedia.org/wiki/String-searching_algorithm) for more details
# on the various algorithms.
#
# We're using the naive algorithm because:
#
# 1. It's easy to implement
# 2. It doesn't require any pre-processing
# 3. At the time of writing there was no need for something more performant
let find_size = value.size
if find_size == 0 or size == 0 or find_size > size { return Option.None }
let mut a = starting_at
let max = size - find_size
while a <= max {
let mut b = 0
while b < find_size and get(a + b) == value.get(b) { b += 1 }
if b == find_size { return Option.Some(a) }
a += 1
}
Option.None
}
fn pub index_of[B: Bytes](value: ref B, starting_at: Int) -> Option[Int]
Returns the byte index of the first occurrence of the given sequence of bytes, starting at the given byte index.
Examples
'hello'.index_of('h', starting_at: 0) # => Option.Some(0)
'hello'.index_of('l', starting_at: 0) # => Option.Some(2)
'hello'.index_of('l', starting_at: 3) # => Option.Some(3)
'hello'.index_of('x', starting_at: 0) # => Option.None
into_byte_array
Show source codeHide source code
fn pub move into_byte_array -> ByteArray {
self
}
fn pub move into_byte_array -> ByteArray
into_string
Show source codeHide source code
fn pub move into_string -> String {
drain_to_string
}
fn pub move into_string -> String
Moves self
into a String
.
iter
Show source codeHide source code
fn pub iter -> Iter[ref Self] {
bytes
}
fn pub iter -> Iter[ref ByteArray]
Returns an iterator over the bytes in self
.
last
Show source codeHide source code
fn pub last -> Option[Int] {
get(size - 1).ok
}
fn pub last -> Option[Int]
Returns the last byte in self
Examples
ByteArray.new.last # => Option.None
ByteArray.from_array([10, 20]).last # => Option.Some(20)
pointer
Show source codeHide source code
fn pub pointer -> Pointer[UInt8] {
@buffer
}
fn pub pointer -> Pointer[UInt8]
Returns a raw pointer to the bytes of self
This method is meant for FFI purposes, and use of it should be avoided at all costs.
pop
Show source codeHide source code
fn pub mut pop -> Option[Int] {
if @size == 0 { return Option.None }
@size -= 1
Option.Some(get_unchecked(@size))
}
fn pub mut pop -> Option[Int]
Removes a value from the back of the ByteArray
, returning the removed
value.
If no value was found, a None is returned instead.
Examples
Popping an existing value:
let bytes = ByteArray.from_array([10])
bytes.pop # => Option.Some(10)
bytes.size # => 0
Popping a value when the ByteArray
is empty:
let bytes = ByteArray.new
bytes.pop # => Option.None
push
Show source codeHide source code
fn pub mut push(value: Int) {
reserve(1)
write_to(@size, value)
@size += 1
}
fn pub mut push(value: Int)
Pushes a value to the back of the ByteArray
, returning the pushed value.
Examples
Pushing a value into a ByteArray
:
let bytes = ByteArray.new
bytes.push(10) # => 10
bytes.size # => 1
remove_at
Show source codeHide source code
fn pub mut remove_at(index: Int) -> Result[Int, OutOfBounds] {
try check_bounds(index, @size)
let addr = address_of(index)
let val = addr.0 as Int
alloc.copy(from: ptr.add(addr, 1), to: addr, size: @size - index - 1)
@size -= 1
Result.Ok(val)
}
fn pub mut remove_at(index: Int) -> Result[Int, OutOfBounds]
Removes the value at the given index, returning the removed value.
Panics
This method panics if the index is out of bounds.
Examples
Removing an existing value:
let bytes = ByteArray.from_array([10])
bytes.remove_at(0) # => 10
bytes.size # => 0
reserve
Show source codeHide source code
fn pub mut reserve(size: Int) {
if @capacity - @size >= size { return }
@capacity = max(@capacity * 2, @capacity + size)
@buffer = alloc.resize(@buffer, @capacity)
}
fn pub mut reserve(size: Int)
Reserves space for size
additional values.
The actual space reserved may be greater to prevent frequent reallocations.
After calling this method, the capacity will be greater than or equal to
self.size + size
.
If the capacity is great enough or the given size is less than zero, this method does nothing.
Examples
let bytes = ByteArray.from_array([1, 2, 3, 4])
bytes.reserve(2)
bytes.capacity # => 8
reserve_exact
Show source codeHide source code
fn pub mut reserve_exact(size: Int) {
if @capacity - @size >= size { return }
@capacity = @capacity + size
@buffer = alloc.resize(@buffer, @capacity)
}
fn pub mut reserve_exact(size: Int)
Reserves space for exactly size
additional values.
Unlike ByteArray.reserve
, this method won't allocate more than the given
amount.
If there's already enough space for size
extra values, this method does
nothing.
Examples
let bytes = ByteArray.new
bytes.reserve_exact(4)
bytes.capacity # => 6
resize
Show source codeHide source code
fn pub mut resize(size: Int, value: Int) {
if size < 0 {
invalid_size(size)
} else if size == @size {
return
} else if size < @size {
@size = size
return
}
let add = size - @capacity
if add > 0 { reserve_exact(add) }
alloc.write(byte: value, to: tail, size: size - @size)
@size = size
}
fn pub mut resize(size: Int, value: Int)
Resizes self
to the new size.
If the given size is greater than the current size, the value
argument is
used to fill in the additional slots. If the given size is less than the
current size, self
is simply truncated.
Panics
This method panics if the given size is less than zero.
Examples
let bytes = ByteArray.new
bytes.resize(size: 2, value: 1)
bytes # => ByteArray.from_array([1, 1])
bytes.resize(size: 0, value: 0)
bytes # => ByteArray.new
reverse
Show source codeHide source code
fn pub mut reverse {
reverse_at(0)
}
fn pub mut reverse
Reverses self
in-place
Examples
let a = ByteArray.from_array([10, 20, 30])
a.reverse
a # => ByteArray.from_array([30, 20, 10])
reverse_at
Show source codeHide source code
fn pub mut reverse_at(index: Int) {
check_bounds(index, size).or_panic
let mut a = index
let mut b = size - 1
while a < b {
let a_val = get_unchecked(a)
let b_val = get_unchecked(b)
write_to(b, a_val)
write_to(a, b_val)
a += 1
b -= 1
}
}
fn pub mut reverse_at(index: Int)
Reverses self
in-place starting at the given index.
Panics
This method panics if the index is out of bounds.
Examples
let a = ByteArray.from_array([10, 20, 30, 40])
a.reverse_at(2)
a # => ByteArray.from_array([10, 20, 40, 30])
set
Show source codeHide source code
fn pub mut set(index: Int, value: Int) {
check_bounds(index, @size).or_panic
write_to(index, value)
}
fn pub mut set(index: Int, value: Int)
Writes the byte value
to the position index
.
Panics
This method panics if the index is out of bounds.
Examples
let bytes = ByteArray.from_array([10, 20])
bytes.set(0, 30)
bytes.get(0) # => 30
size
Show source codeHide source code
fn pub inline size -> Int {
@size
}
fn pub inline size -> Int
Returns the number of bytes in self
.
Examples
ByteArray.new.size # => 0
ByteArray.from_array([10]).size # => 1
slice
Show source codeHide source code
fn pub slice(start: Int, end: Int) -> Slice[Self] {
Slice.checked(self, start, end)
}
fn pub slice(start: Int, end: Int) -> Slice[ByteArray]
Returns a Slice
over self
from start
until (but excluding) end
.
Because a ByteArray
is a mutable type it's possible for the values covered
by a Slice
to change. While the Slice
type handles such cases (e.g. if
the ByteArray
is cleared, a Slice
doesn't produce any values), it's best
not to modify self
when slices to it exist as this may result in
confusing/unexpected behavior.
The start
index is allowed to be equal to the size of self
, but only if
end
is the same as start
. Thus given a ByteArray
with a size of 4
,
the range 4 until 4
is valid.
Panics
This method panics if start
or end
is out of bounds.
Examples
Slicing a ByteArray
:
let bytes = ByteArray.from_array([1, 2, 3, 4])
let slice = bytes.slice(start: 1, end: 3)
slice.get(0) # => 2
slice.get(1) # => 3
Slicing a ByteArray
and updating the underlying values:
let bytes = ByteArray.from_array([1, 2, 3, 4])
let slice = bytes.slice(start: 1, end: 3)
slice.get(0) # => 1
bytes.set(0, 10)
slice.get(0) # => 10
starts_with?
Show source codeHide source code
fn pub starts_with?[T: Bytes](prefix: ref T) -> Bool {
ptr.starts_with?(@buffer, size, prefix.pointer, prefix.size)
}
fn pub starts_with?[T: Bytes](prefix: ref T) -> Bool
Returns true
if self
starts with the given sequence of bytes.
Examples
'hello'.to_byte_array.starts_with?('h'.to_byte_array) # => true
'hello'.to_byte_array.starts_with?('h') # => true
to_array
Show source codeHide source code
fn pub to_array -> Array[Int] {
iter.to_array
}
fn pub to_array -> Array[Int]
Converts the ByteArray
to an Array!(Int)
.
Examples
Converting a ByteArray
:
let bytes = ByteArray.from_array([105, 110, 107, 111])
bytes.to_array # => [105, 110, 107, 111]
to_byte_array
Show source codeHide source code
fn pub to_byte_array -> ByteArray {
clone
}
fn pub to_byte_array -> ByteArray
to_string
Show source codeHide source code
fn pub to_string -> String {
if empty? { return '' }
String.from_primitive(inko_string_from_bytes(@buffer, @size))
}
fn pub to_string -> String
Returns a new String
using the bytes in this ByteArray
.
Any invalid UTF-8 sequences will be replaced with U+FFFD REPLACEMENT
CHARACTER
, which looks like this: �
Examples
Converting a ByteArray
into a String
:
let bytes = ByteArray.from_array([105, 110, 107, 111])
bytes.to_string # => 'inko'
zero
Show source codeHide source code
fn pub mut zero {
alloc.zero(pointer, size)
}
fn pub mut zero
Overwrites all bytes in self
with zero bytes.
Note that until this issue is resolved, the compiler might optimize code such that the writing of the zero bytes is optimized away.
Examples
let bytes = ByteArray.from_array([1, 2, 3])
bytes.zero
bytes # => ByteArray.from_array([0, 0, 0])
Implemented traits
Bytes
impl Bytes for ByteArray
IntoByteArray
impl IntoByteArray for ByteArray
ToByteArray
impl ToByteArray for ByteArray
Clone
impl Clone for ByteArray
Equal
impl Equal for ByteArray
Drop
impl Drop for ByteArray
Format
impl Format for ByteArray
Hash
impl Hash for ByteArray
IntoString
impl IntoString for ByteArray
ToString
impl ToString for ByteArray