iyi

Standard library, 0.18.0

std/slice

Slice, a bounded pointer — SPEC.md III.

import std/slice to use it. Source: src/std/slice.iyi at v0.18.0.

A Slice(T) is a Pointer(T) with a size and a read-only flag. While raw pointers are unchecked and unsafe, a slice enforces bounds checks on reads and writes, provides safe subslicing, in-place manipulation, and integrates with Enumerable.

Bytes is an alias for Slice(UInt8), the currency of IO, sockets, and binary protocols.

Bytesalias

pub, because an alias is part of a module's surface like anything else: an unexported one is unreachable from a consumer, which R-2 now says out loud.

std/sliceiyi doc src/std/slice.iyi
pub alias Bytes = Slice(UInt8)

Slice(T)struct

std/sliceiyi doc src/std/slice.iyi
pub struct Slice(T)
  # Returns a subslice starting *offset* elements in, extending to the end.
  def +(offset : Int32) : Slice(T)
  # Returns true if sizes match and all elements are equal.
  #
  # A slice of its own element type, as `Array#==` takes an `Array(T)`. It
  # took any `Slice(U)`, and numbers that compare equal across types hash
  # apart: `Slice[-1, -2]` of `Int32` was `==` to the same of `Int64` with
  # hashes 204952928 and -1576659145, so a table missed one by the other.
  def ==(other : Slice(T)) : Bool
  def ==(other : Object) : Bool
  # Returns a subslice of *count* elements starting at *start*.
  def [](start : Int32, count : Int32) : Slice(T)
  # Element access with bounds checking. A negative index counts from the end,
  # so `s[-1]` is the last element; the message names the index as typed rather
  # than the wrapped one, and words it exactly as `Array#[]` and
  # `Indexable#[]` do — the same mistake reads the same way in all three.
  def [](index : Int32) : T
  # Returns a subslice covering *range*.
  def [](range : Range(Int32, Int32)) : Slice(T)
  # Element assignment with bounds checking and write-protection check.
  def []=(index : Int32, value : T) : T
  # Returns a subslice of *count* elements starting at *start*, or nil if out of bounds.
  def []?(start : Int32, count : Int32) : Slice(T) | ::Nil
  # Element access with bounds checking, returning nil if out of bounds.
  def []?(index : Int32) : T | ::Nil
  # Returns a subslice covering *range*, or nil if out of bounds.
  #
  # A range that ends before it begins is empty, not out of bounds, as the
  # other library counts it: `s[3..1]` is the empty slice at 3. The count is
  # taken only once the end is known to be past the start, and the
  # inclusive end is added only while the count can still fit, so an end
  # near the top of `Int32` answers nil instead of overflowing.
  def []?(range : Range(Int32, Int32)) : Slice(T) | ::Nil
  # Returns the total size in bytes of this slice's elements.
  def bytesize : Int32
  # Returns a copy of this slice.
  def clone : Slice(T)
  # Copies *count* elements from raw *source* pointer into this slice.
  def copy_from(source : Pointer(T), count : Int32) : Nil
  # Copies all elements from *source* slice into this slice.
  def copy_from(source : Slice(T)) : Nil
  # Copies *count* elements from this slice to raw *target* pointer.
  def copy_to(target : Pointer(T), count : Int32) : Nil
  # Copies all elements from this slice to *target* slice.
  def copy_to(target : Slice(T)) : Nil
  # Returns a new slice with copied contents. The copy is filled before it
  # takes this slice's read-only flag: `copy_from` into a read-only copy
  # refused, so a read-only slice could not be duplicated at all.
  def dup : Slice(T)
  # Yields each element and its index to the block.
  def each_with_index(& : (T, Int32 -> Nil)) : Nil
  # Returns an empty slice of size 0.
  def self.empty : self
  # Returns true if the slice contains no elements.
  def empty? : Bool
  # Fills *count* elements starting at *start* with *value*.
  def fill(value : T, start : Int32, count : Int32) : self
  # Fills the entire slice with *value*.
  def fill(value : T) : self
  # Fills the entire slice by yielding each index to the block.
  def fill(& : (Int32 -> T)) : self
  # Returns a lowercase hex string representation of Bytes.
  def hexstring : String
  # Creates a slice wrapping *pointer* bounded by *size*.
  #
  # `read_only` is named in this and every `Slice.new`, as in the other
  # library. Positional, it took the value's place when `T` is `Bool`:
  # `Slice(Bool).new(3, true)` was `Slice[false, false, false]`, read-only.
  def initialize(pointer : Pointer(T), size : Int32, *, read_only : Bool = false)
  def inspect : String
  # Moves *count* elements from *source* pointer into this slice, safely handling overlaps.
  def move_from(source : Pointer(T), count : Int32) : Nil
  # Moves all elements from *source* slice into this slice, safely handling overlaps.
  def move_from(source : Slice(T)) : Nil
  # Moves *count* elements from this slice into *target* pointer, safely handling overlaps.
  def move_to(target : Pointer(T), count : Int32) : Nil
  # Moves all elements from this slice into *target* slice, safely handling overlaps.
  def move_to(target : Slice(T)) : Nil
  # Allocates a slice of *size* elements initialized to *value*.
  #
  # These three answer `Slice(T)`, not `self`, as `Array.new` does: when the
  # element type is left to the value or the block, `self` is still the
  # unbound `Slice(T)` while the body builds `Slice(Int32)`, so
  # `Slice.new(3) { |i| i + 1 }` and `Slice.new(3, 7)` did not compile.
  def self.new(size : Int32, value : T, *, read_only : Bool = false) : Slice(T)
  # Allocates a slice of *size* elements on the heap.
  def self.new(size : Int32, *, read_only : Bool = false) : self
  # Allocates a slice of *size* elements initialized by yielding each index.
  def self.new(size : Int32, & : (Int32 -> T)) : Slice(T)
  def self.new(size : Int32, *, read_only : Bool, & : (Int32 -> T)) : Slice(T)
  def read_only? : Bool
  # Reverses the elements of the slice in-place.
  def reverse : self
  def reverse_in_place : self
  # Returns true if this slice and *other* point to the exact same memory and have the same size.
  def same?(other : Slice(T)) : Bool
  def size : Int32
  # Swaps elements at index *i* and index *j*.
  def swap(i : Int32, j : Int32) : self
  # Returns an Array containing all elements in this slice.
  def to_a : Array(T)
  # String representation: Bytes[...] for Slice(UInt8), Slice[...] for others.
  def to_s : String
  # Raw pointer to the underlying buffer.
  def to_unsafe : Pointer(T)
  # Raw element access without bounds checks (required for Indexable).
  def unsafe_fetch(index : Int32) : T
  # Raw element write without bounds checks.
  def unsafe_put(index : Int32, value : T) : T
end

SliceIterator(T)class

The lazy half, which Slice had no way into: std/iterator's header says a concrete collection provides its own iterator constructor and names this type twice as one that should, and then the only route from a slice to a lazy chain was fs.to_a — copying the whole sequence, which is the cost the tower exists to avoid.

A class, as ArrayIterator is (std/iterator): an adaptor keeps its source by value, and a struct source was copied into it, so it.first(2).to_a and then it.to_a gave [1, 2] and [1, 2, 3, 4] where an array's iterator gives [1, 2] and [3, 4].

std/sliceiyi doc src/std/slice.iyi
pub class SliceIterator(T)
  def initialize(slice : Slice(T))
  def next : T | Stop
end

Std::Indexable::Indexable for Slice(T) forall Timpl

std/sliceiyi doc src/std/slice.iyi
impl Std::Indexable::Indexable for Slice(T) forall T
end

Std::Enumerable::Enumerable for Slice(T) forall Timpl

std/sliceiyi doc src/std/slice.iyi
impl Std::Enumerable::Enumerable for Slice(T) forall T
  def each(& : (T -> Nil)) : Nil
end

Std::Iterator::Iterator for SliceIterator(T) forall Timpl

std/sliceiyi doc src/std/slice.iyi
impl Std::Iterator::Iterator for SliceIterator(T) forall T
end