struct Slice(T)

Overview

A Slice is a Pointer with an associated size.

While a pointer is unsafe because no bound checks are performed when reading from and writing to it, reading from and writing to a slice involve bound checks. In this way, a slice is a safe alternative to Pointer.

A Slice can be created as read-only: trying to write to it will raise. For example the slice of bytes returned by String#to_slice is read-only.

Included Modules

Defined in:

slice.cr
slice/sort.cr
yaml/from_yaml.cr
yaml/to_yaml.cr

Constructors

Class Method Summary

Instance Method Summary

Macro Summary

Instance methods inherited from module Comparable(Slice(T))

<(other : T) <, <=(other : T) <=, <=>(other : T) <=>, ==(other : T) ==, >(other : T) >, >=(other : T) >=, clamp(min, max)
clamp(range : Range)
clamp

Instance methods inherited from module Indexable(T)

[](index : Int) [], []?(index : Int) []?, bsearch(&block : T -> Bool) bsearch, bsearch_index(&block : T, Int32 -> Bool) bsearch_index, combinations(size : Int = self.size) combinations, dig(index : Int, *subindexes) dig, dig?(index : Int, *subindexes) dig?, each(*, within range : Range, &)
each
each(&)
each(*, start : Int, count : Int, &)
each
, each_combination(size : Int = self.size, reuse = false, &) : Nil
each_combination(size : Int = self.size, reuse = false)
each_combination
, each_index(&) : Nil
each_index
each_index(*, start : Int, count : Int, &)
each_index
, each_permutation(size : Int = self.size, reuse = false)
each_permutation(size : Int = self.size, reuse = false, &) : Nil
each_permutation
, each_repeated_combination(size : Int = self.size, reuse = false, &) : Nil
each_repeated_combination(size : Int = self.size, reuse = false)
each_repeated_combination
, empty? empty?, equals?(other : Indexable, &)
equals?(other, &)
equals?
, fetch(index, default)
fetch(index : Int, &)
fetch
, first(&) first, hash(hasher) hash, index(offset : Int = 0, &)
index(object, offset : Int = 0)
index
, join(separator : String | Char | Number = "") join, last
last(&)
last
, last? last?, permutations(size : Int = self.size) permutations, repeated_combinations(size : Int = self.size) repeated_combinations, reverse_each(&) : Nil
reverse_each
reverse_each
, rindex(value, offset = size - 1)
rindex(offset = size - 1, &)
rindex
, sample(random = Random::DEFAULT) sample, size size, to_a to_a, unsafe_fetch(index : Int) unsafe_fetch, values_at(*indexes : Int) values_at

Instance methods inherited from module Enumerable(T)

all?(&)
all?(pattern)
all?
all?
, any?(&)
any?(pattern)
any?
any?
, chunks(&block : T -> U) forall U chunks, compact_map(&) compact_map, count(&)
count(item)
count
, cycle(&)
cycle(n, &)
cycle
, each(&block : T -> _) each, each_cons(count : Int, reuse = false, &) each_cons, each_cons_pair(& : T, T -> _) : Nil each_cons_pair, each_slice(count : Int, reuse = false, &) each_slice, each_with_index(offset = 0, &) each_with_index, each_with_object(obj, &) each_with_object, empty? empty?, find(if_none = nil, &) find, first(&)
first(count : Int)
first
first
, first? first?, flat_map(&block : T -> Array(U) | Iterator(U) | U) forall U flat_map, group_by(&block : T -> U) forall U group_by, in_groups_of(size : Int, filled_up_with : U = nil) forall U
in_groups_of(size : Int, filled_up_with : U = nil, reuse = false, &) forall U
in_groups_of
, includes?(obj) includes?, index(&)
index(obj)
index
, index_by(&block : T -> U) forall U index_by, join(separator = "", & : T -> )
join(separator, io : IO, &)
join(io : IO, separator = "", & : T, IO -> )
join(separator = "")
join(separator, io : IO)
join(io : IO, separator = "")
join
, map(&block : T -> U) forall U map, map_with_index(offset = 0, &block : T, Int32 -> U) forall U map_with_index, max max, max? max?, max_by(&block : T -> U) forall U max_by, max_by?(&block : T -> U) forall U max_by?, max_of(&block : T -> U) forall U max_of, max_of?(&block : T -> U) forall U max_of?, min min, min? min?, min_by(&block : T -> U) forall U min_by, min_by?(&block : T -> U) forall U min_by?, min_of(&block : T -> U) forall U min_of, min_of?(&block : T -> U) forall U min_of?, minmax minmax, minmax? minmax?, minmax_by(&block : T -> U) forall U minmax_by, minmax_by?(&block : T -> U) forall U minmax_by?, minmax_of(&block : T -> U) forall U minmax_of, minmax_of?(&block : T -> U) forall U minmax_of?, none?(pattern)
none?(&)
none?
none?
, one?(&)
one?(pattern)
one?
one?
, partition(&) partition, product(initial : Number)
product
product(initial : Number, &)
product(&)
product
, reduce(memo, &)
reduce(&)
reduce
, reduce?(&) reduce?, reject(pattern)
reject(type : U.class) forall U
reject(&block : T -> )
reject
, sample(n : Int, random = Random::DEFAULT)
sample(random = Random::DEFAULT)
sample
, select(pattern)
select(type : U.class) forall U
select(&block : T -> )
select
, size size, skip(count : Int) skip, skip_while(&) skip_while, sum(initial)
sum
sum(initial, &)
sum(&)
sum
, take_while(&) take_while, tally : Hash(T, Int32) tally, to_a to_a, to_h
to_h(&block : T -> Tuple(K, V)) forall K, V
to_h
, to_set to_set, zip(*others : Indexable | Iterable | Iterator, &)
zip(*others : Indexable | Iterable | Iterator)
zip
, zip?(*others : Indexable | Iterable | Iterator, &)
zip?(*others : Indexable | Iterable | Iterator)
zip?

Instance methods inherited from module Iterable(T)

chunk(reuse = false, &block : T -> U) forall U chunk, chunk_while(reuse : Bool | Array(T) = false, &block : T, T -> B) forall B chunk_while, cycle(n)
cycle
cycle
, each each, each_cons(count : Int, reuse = false) each_cons, each_slice(count : Int, reuse = false) each_slice, each_with_index(offset = 0) each_with_index, each_with_object(obj) each_with_object, slice_after(reuse : Bool | Array(T) = false, &block : T -> B) forall B
slice_after(pattern, reuse : Bool | Array(T) = false)
slice_after
, slice_before(reuse : Bool | Array(T) = false, &block : T -> B) forall B
slice_before(pattern, reuse : Bool | Array(T) = false)
slice_before
, slice_when(reuse : Bool | Array(T) = false, &block : T, T -> B) forall B slice_when

Instance methods inherited from struct Struct

==(other) : Bool ==, hash(hasher) hash, inspect(io : IO) : Nil inspect, pretty_print(pp) : Nil pretty_print, to_s(io : IO) : Nil to_s

Instance methods inherited from struct Value

==(other : JSON::Any)
==(other : YAML::Any)
==(other)
==
, dup dup

Instance methods inherited from class Object

! : Bool !, !=(other) !=, !~(other) !~, ==(other) ==, ===(other : JSON::Any)
===(other : YAML::Any)
===(other)
===
, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash
hash
, in?(*values : Object) : Bool
in?(collection) : Bool
in?
, inspect : String
inspect(io : IO) : Nil
inspect
, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO)
to_json
to_json
, to_pretty_json(io : IO, indent : String = " ")
to_pretty_json(indent : String = " ")
to_pretty_json
, to_s : String
to_s(io : IO) : Nil
to_s
, to_yaml(io : IO)
to_yaml
to_yaml
, try(&) try, unsafe_as(type : T.class) forall T unsafe_as

Class methods inherited from class Object

from_json(string_or_io, root : String)
from_json(string_or_io)
from_json
, from_yaml(string_or_io : String | IO) from_yaml

Constructor Detail

def self.new(ctx : YAML::ParseContext, node : YAML::Nodes::Node) #

[View source]
def self.new(pointer : Pointer(T), size : Int, *, read_only = false) #

Creates a slice to the given pointer, bounded by the given size. This method does not allocate heap memory.

ptr = Pointer.malloc(9) { |i| ('a'.ord + i).to_u8 }

slice = Slice.new(ptr, 3)
slice.size # => 3
slice      # => Bytes[97, 98, 99]

String.new(slice) # => "abc"

[View source]
def self.new(size : Int, value : T, *, read_only = false) #

Allocates size * sizeof(T) bytes of heap memory initialized to value and returns a slice pointing to that memory.

The memory is allocated by the GC, so when there are no pointers to this memory, it will be automatically freed.

slice = Slice.new(3, 10)
slice # => Slice[10, 10, 10]

[View source]
def self.new(size : Int, *, read_only = false) #

Allocates size * sizeof(T) bytes of heap memory initialized to zero and returns a slice pointing to that memory.

The memory is allocated by the GC, so when there are no pointers to this memory, it will be automatically freed.

Only works for primitive integers and floats (UInt8, Int32, Float64, etc.)

slice = Slice(UInt8).new(3)
slice # => Bytes[0, 0, 0]

[View source]
def self.new(size : Int, *, read_only = false, &) #

Allocates size * sizeof(T) bytes of heap memory initialized to the value returned by the block (which is invoked once with each index in the range 0...size) and returns a slice pointing to that memory.

The memory is allocated by the GC, so when there are no pointers to this memory, it will be automatically freed.

slice = Slice.new(3) { |i| i + 10 }
slice # => Slice[10, 11, 12]

[View source]

Class Method Detail

def self.empty #

Creates an empty slice.

slice = Slice(UInt8).empty
slice.size # => 0

[View source]

Instance Method Detail

def +(offset : Int) #

Returns a new slice that is offset elements apart from this slice.

slice = Slice.new(5) { |i| i + 10 }
slice # => Slice[10, 11, 12, 13, 14]

slice2 = slice + 2
slice2 # => Slice[12, 13, 14]

[View source]
def <=>(other : Slice(U)) forall U #

Combined comparison operator.

Returns a negative number, 0, or a positive number depending on whether self is less than other, equals other.

It compares the elements of both slices in the same position using the #<=> operator. As soon as one of such comparisons returns a non-zero value, that result is the return value of the comparison.

If all elements are equal, the comparison is based on the size of the arrays.

Bytes[8] <=> Bytes[1, 2, 3] # => 7
Bytes[2] <=> Bytes[4, 2, 3] # => -2
Bytes[1, 2] <=> Bytes[1, 2] # => 0

[View source]
def ==(other : Slice(U)) : Bool forall U #

Returns true if self and other have the same size and all their elements are equal, false otherwise.

Bytes[1, 2] == Bytes[1, 2]    # => true
Bytes[1, 3] == Bytes[1, 2]    # => false
Bytes[1, 2] == Bytes[1, 2, 3] # => false

[View source]
def [](range : Range) #

Returns a new slice with the elements in the given range.

Negative indices count backward from the end of the slice (-1 is the last element). Additionally, an empty slice is returned when the starting index for an element range is at the end of the slice.

Raises IndexError if the new slice falls outside this slice.

slice = Slice.new(5) { |i| i + 10 }
slice # => Slice[10, 11, 12, 13, 14]

slice[1..3]  # => Slice[11, 12, 13]
slice[1..33] # raises IndexError

[View source]
def [](start : Int, count : Int) #

Returns a new slice that starts at start elements from this slice's start, and of count size.

Raises IndexError if the new slice falls outside this slice.

slice = Slice.new(5) { |i| i + 10 }
slice # => Slice[10, 11, 12, 13, 14]

slice[1, 3]  # => Slice[11, 12, 13]
slice[1, 33] # raises IndexError

[View source]
def []=(index : Int, value : T) #

Sets the given value at the given index.

Negative indices can be used to start counting from the end of the slice. Raises IndexError if trying to set an element outside the slice's range.

slice = Slice.new(5) { |i| i + 10 }
slice[0] = 20
slice[-1] = 30
slice # => Slice[20, 11, 12, 13, 30]

slice[10] = 1 # raises IndexError

[View source]
def []?(start : Int, count : Int) #

Returns a new slice that starts at start elements from this slice's start, and of count size.

Returns nil if the new slice falls outside this slice.

slice = Slice.new(5) { |i| i + 10 }
slice # => Slice[10, 11, 12, 13, 14]

slice[1, 3]?  # => Slice[11, 12, 13]
slice[1, 33]? # => nil

[View source]
def []?(range : Range) #

Returns a new slice with the elements in the given range.

Negative indices count backward from the end of the slice (-1 is the last element). Additionally, an empty slice is returned when the starting index for an element range is at the end of the slice.

Returns nil if the new slice falls outside this slice.

slice = Slice.new(5) { |i| i + 10 }
slice # => Slice[10, 11, 12, 13, 14]

slice[1..3]?  # => Slice[11, 12, 13]
slice[1..33]? # => nil

[View source]
def bytesize #

[View source]
def clone #

Returns a deep copy of this slice.

This method allocates memory for the slice copy and stores the return values from calling #clone on each item.


[View source]
def copy_from(source : Pointer(T), count) #

[View source]
def copy_from(source : self) #

Copies the contents of source into this slice.

Raises IndexError if the destination slice cannot fit the data being transferred.


[View source]
def copy_to(target : Pointer(T), count) #

[View source]
def copy_to(target : self) #

Copies the contents of this slice into target.

Raises IndexError if the destination slice cannot fit the data being transferred e.g. dest.size < self.size.

src = Slice['a', 'a', 'a']
dst = Slice['b', 'b', 'b', 'b', 'b']
src.copy_to dst
dst             # => Slice['a', 'a', 'a', 'b', 'b']
dst.copy_to src # raises IndexError

[View source]
def dup #

Returns a shallow copy of this slice.

This method allocates memory for the slice copy and duplicates the values.


[View source]
def hash(hasher) #

[View source]
def hexdump #

Returns a hexdump of this slice, assuming it's a Slice(UInt8). This method is specially useful for debugging binary data and incoming/outgoing data in protocols.

slice = UInt8.slice(97, 62, 63, 8, 255)
slice.hexdump # => "00000000  61 3e 3f 08 ff                                    a>?.."

[View source]
def hexstring #

Returns a hexstring representation of this slice, assuming it's a Slice(UInt8).

slice = UInt8.slice(97, 62, 63, 8, 255)
slice.hexstring # => "613e3f08ff"

[View source]
def inspect(io : IO) : Nil #
Description copied from struct Struct

Appends this struct's name and instance variables names and values to the given IO.

struct Point
  def initialize(@x : Int32, @y : Int32)
  end
end

p1 = Point.new 1, 2
p1.to_s    # "Point(@x=1, @y=2)"
p1.inspect # "Point(@x=1, @y=2)"

[View source]
def map(*, read_only = false, &block : T -> U) forall U #

Returns a new slice where elements are mapped by the given block.

slice = Slice[1, 2.5, "a"]
slice.map &.to_s # => Slice["1", "2.5", "a"]

[View source]
def map!(&) #

Invokes the given block for each element of self, replacing the element with the value returned by the block. Returns self.

slice = Slice[1, 2, 3]
slice.map! { |x| x * x }
slice # => Slice[1, 4, 9]

[View source]
def map_with_index(offset = 0, *, read_only = false, &block : T, Int32 -> U) forall U #

Like #map, but the block gets passed both the element and its index.

Accepts an optional offset parameter, which tells it to start counting from there.


[View source]
def map_with_index!(offset = 0, &block : T, Int32 -> T) #

Like #map!, but the block gets passed both the element and its index.

Accepts an optional offset parameter, which tells it to start counting from there.


[View source]
def move_from(source : Pointer(T), count) #

[View source]
def move_from(source : self) #

Moves the contents of source into this slice. source and self may overlap; the copy is always done in a non-destructive manner.

Raises IndexError if the destination slice cannot fit the data being transferred.


[View source]
def move_to(target : Pointer(T), count) #

[View source]
def move_to(target : self) #

Moves the contents of this slice into target. target and self may overlap; the copy is always done in a non-destructive manner.

Raises IndexError if the destination slice cannot fit the data being transferred e.g. dest.size < self.size.

src = Slice['a', 'a', 'a']
dst = Slice['b', 'b', 'b', 'b', 'b']
src.move_to dst
dst             # => Slice['a', 'a', 'a', 'b', 'b']
dst.move_to src # raises IndexError

See also: Pointer#move_to.


[View source]
def pretty_print(pp) : Nil #

[View source]
def read_only? : Bool #

Returns true if this slice cannot be written to.


[View source]
def reverse! #

Reverses in-place all the elements of self.


[View source]
def shuffle!(random = Random::DEFAULT) #

[View source]
def size : Int32 #

Returns the size of this slice.

Slice(UInt8).new(3).size # => 3

[View source]
def sort : Slice(T) #

Returns a new slice with all elements sorted based on the return value of their comparison method #<=>

a = Slice[3, 1, 2]
a.sort # => Slice[1, 2, 3]
a      # => Slice[3, 1, 2]

[View source]
def sort(&block : T, T -> U) : Slice(T) forall U #

Returns a new slice with all elements sorted based on the comparator in the given block.

The block must implement a comparison between two elements a and b, where a < b returns -1, a == b returns 0, and a > b returns 1. The comparison operator #<=> can be used for this.

a = Slice[3, 1, 2]
b = a.sort { |a, b| b <=> a }

b # => Slice[3, 2, 1]
a # => Slice[3, 1, 2]

[View source]
def sort! : Slice(T) #

Modifies self by sorting all elements based on the return value of their comparison method #<=>

a = Slice[3, 1, 2]
a.sort!
a # => Slice[1, 2, 3]

[View source]
def sort!(&block : T, T -> U) : Slice(T) forall U #

Modifies self by sorting all elements based on the comparator in the given block.

The given block must implement a comparison between two elements a and b, where a < b returns -1, a == b returns 0, and a > b returns 1. The comparison operator #<=> can be used for this.

a = Slice[3, 1, 2]
a.sort! { |a, b| b <=> a }
a # => Slice[3, 2, 1]

[View source]
def sort_by(&block : T -> _) : Slice(T) #

Returns a new array with all elements sorted. The given block is called for each element, then the comparison method #<=> is called on the object returned from the block to determine sort order.

a = Slice["apple", "pear", "fig"]
b = a.sort_by { |word| word.size }
b # => Slice["fig", "pear", "apple"]
a # => Slice["apple", "pear", "fig"]

[View source]
def sort_by!(&block : T -> _) : Slice(T) #

Modifies self by sorting all elements. The given block is called for each element, then the comparison method #<=> is called on the object returned from the block to determine sort order.

a = Slice["apple", "pear", "fig"]
a.sort_by! { |word| word.size }
a # => Slice["fig", "pear", "apple"]

[View source]
def to_a #
Description copied from module Indexable(T)

Returns an Array with all the elements in the collection.

{1, 2, 3}.to_a # => [1, 2, 3]

[View source]
def to_s(io : IO) : Nil #
Description copied from struct Struct

Same as #inspect(io).


[View source]
def to_slice #

[View source]
def to_unsafe : Pointer(T) #

Returns this slice's pointer.

slice = Slice.new(3, 10)
slice.to_unsafe[0] # => 10

[View source]
def to_yaml(yaml : YAML::Nodes::Builder) #

[View source]
def unsafe_fetch(index : Int) #
Description copied from module Indexable(T)

Returns the element at the given index, without doing any bounds check.

Indexable makes sure to invoke this method with index in 0...size, so converting negative indices to positive ones is not needed here.

Clients never invoke this method directly. Instead, they access elements with #[](index) and #[]?(index).

This method should only be directly invoked if you are absolutely sure the index is in bounds, to avoid a bounds check for a small boost of performance.


[View source]

Macro Detail

macro [](*args, read_only = false) #

Creates a new Slice with the given args. The type of the slice will be the union of the type of the given args.

The slice is allocated on the heap.

slice = Slice[1, 'a']
slice[0]    # => 1
slice[1]    # => 'a'
slice.class # => Slice(Char | Int32)

If T is a Number then this is equivalent to Number.slice (numbers will be coerced to the type T)

See also: Number.slice.


[View source]