Search results

There are no results.

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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide source code
fn pub move into_byte_array -> ByteArray {
  self
}
fn pub move into_byte_array -> ByteArray

into_string

Show source code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide 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 code
Hide source code
fn pub to_byte_array -> ByteArray {
  clone
}
fn pub to_byte_array -> ByteArray

to_string

Show source code
Hide 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 code
Hide 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

std.bytes.

Bytes

impl Bytes for ByteArray
std.bytes.

IntoByteArray

impl IntoByteArray for ByteArray
std.bytes.

ToByteArray

impl ToByteArray for ByteArray
std.clone.

Clone

impl Clone for ByteArray
std.cmp.

Equal

impl Equal for ByteArray
std.drop.

Drop

impl Drop for ByteArray
std.fmt.

Format

impl Format for ByteArray
std.hash.

Hash

impl Hash for ByteArray
std.string.

IntoString

impl IntoString for ByteArray
std.string.

ToString

impl ToString for ByteArray