Class Subspace :: sus :: collections :: Slice

template <class T>
class Slice final
{ ... };

A dynamically-sized const view into a contiguous sequence of objects of type const T.

Contiguous here means that elements are laid out so that every element is the same distance from its neighbors, where there are sus::mem::size_of<T>() many bytes between the start of each element.

Slices are a view into a block of memory represented as a pointer and a length.

Static Methods

Constructs an empty Slice.

This constructor is implicit so that using the EmptyMarker allows the caller to avoid spelling out the full Slice type.

Constructs an empty Slice, which has no elements.

template <size_t N>
static auto from(const T (&data)[N]) -> Slice<T>
requires
N <= ::sus::cast<usize>(isize::MAX)

sus::construct::From<T[N]> trait.

Returns a Slice that refers to all elements of the data array.

static auto from_raw_collection(UnsafeFnMarker, IterRefCounter refs, const T* data, sus::usize len) -> Slice<T>

Constructs a slice from its raw parts with iterator invalidation tracking. Iterators produced from this slice will interact with the collection to allow it to know when they are being invalidated by the collection.

For building a Slice from primitive pointer, use from_raw_parts().

Safety

The following must be upheld or Undefined Behaviour may result:

  • The len must be no more than the number of elements in the allocation at and after the position of data.
  • The pointer data must be a valid pointer to an allocation, not a dangling pointer, at any point during the Slice's lifetime. This must be true even if len is 0.
  • The refs will be sus::iter::IterRefCounter::empty_for_view() unless the Slice is being constructed from a context that owns an IterRefCounter and wants to be able to observe when it invalidates the Slice by tracking its lifetime.

In some other langages such as Rust, the slice may hold an invalid pointer when the length is zero. But Slice must not hold a dangling pointer. Otherwise addition on the dangling pointer may happen in Slice methods, which is Undefined Behaviour in C++. To support dangling pointers, those methods would need length == 0 branches. Care must be applied when converting slices between languages as a result.

static auto from_raw_parts(UnsafeFnMarker, const T* data, sus::usize len) -> Slice<T>

Constructs a slice from its raw parts.

For building a Slice from a collection, use from_raw_collection() in order to participate in iterator invalidation tracking.

Safety

The following must be upheld or Undefined Behaviour may result:

  • The len must be no more than the number of elements in the allocation at and after the position of data.
  • The pointer data must be a valid pointer to an allocation, not a dangling pointer, at any point during the Slice's lifetime. This must be true even if len is 0.
  • The refs will be sus::iter::IterRefCounter::empty_for_view() unless the Slice is being constructed from a context that owns an IterRefCounter and wants to be able to observe when it invalidates the Slice by tracking its lifetime.

In some other langages such as Rust, the slice may hold an invalid pointer when the length is zero. But Slice must not hold a dangling pointer. Otherwise addition on the dangling pointer may happen in Slice methods, which is Undefined Behaviour in C++. To support dangling pointers, those methods would need length == 0 branches. Care must be applied when converting slices between languages as a result.

Methods

auto as_ptr() const& -> const T*

Returns a const pointer to the first element in the slice.

The caller must ensure that the collection outlives the pointer this function returns, or else it will end up pointing to garbage.

Modifying the collection referenced by this slice may cause its buffer to be reallocated, which would also make any pointers to it invalid.

auto as_ptr_range() const& -> Range<const T*>

Returns the two const pointers spanning the slice.

The returned range is half-open, which means that the end pointer points one past the last element of the slice. This way, an empty slice is represented by two equal pointers, and the difference between the two pointers represents the size of the slice.

The end pointer requires caution, as it does not point to a valid element in the slice.

This function is useful for interacting with interfaces which use two pointers to refer to a range of elements in memory, as is common in C++ stdlib algorthms. Note that the pointers can be unpacked from the Range with structured bindings as in auto [a, b] = s.as_ptr_range();.

auto binary_search(const T& x) const& -> Result<usize, usize>
requires
sus::cmp::Ord<T>

Binary searches this slice for a given element. This behaves similarly to contains if this slice is sorted.

If the value is found then sus::Ok is returned, with the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Subspace. If the value is not found then sus::Err is returned, with the index where a matching element could be inserted while maintaining sorted order.

auto binary_search_by(FnMut<std::weak_ordering(const T&)> auto f) const& -> Result<usize, usize>

Binary searches this slice with a comparator function. This behaves similarly to contains if this slice is sorted.

The comparator function should implement an order consistent with the sort order of the underlying slice, returning a std::strong_ordering that indicates whether its argument is less than, equal to or greater than the desired target.

If the value is found then sus::Ok is returned, with the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Subspace. If the value is not found then sus::Err is returned, with the index where a matching element could be inserted while maintaining sorted order.

template <class Key>
auto binary_search_by_key(const Key& key, FnMut<Key(const T&)> auto f) const& -> Result<usize, usize>
requires
sus::cmp::StrongOrd<Key>

Binary searches this slice with a key extraction function. This behaves similarly to contains if this slice is sorted.

Assumes that the slice is sorted by the key, for instance with sort_by_key using the same key extraction function.

If the value is found then sus::Ok is returned, with the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Subspace. If the value is not found then sus::Err is returned, with the index where a matching element could be inserted while maintaining sorted order.

auto chunks(usize chunk_size) const& -> Chunks<T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the beginning of the slice.

The chunks are slices and do not overlap. If chunk_size does not divide the length of the slice, then the last chunk will not have length chunk_size.

See chunks_exact() for a variant of this iterator that returns chunks of always exactly chunk_size elements, and rchunks() for the same iterator but starting at the end of the slice.

Panics

Panics if chunk_size is 0.

auto chunks_exact(usize chunk_size) const& -> ChunksExact<T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the beginning of the slice.

The chunks are slices and do not overlap. If chunk_size does not divide the length of the slice, then the last up to chunk_size-1 elements will be omitted and can be retrieved from the remainder function of the iterator.

TODO: Verify if: due to each chunk having exactly chunk_size elements, the compiler can often optimize the resulting code better than in the case of chunks().

See chunks() for a variant of this iterator that also returns the remainder as a smaller chunk, and rchunks_exact() for the same iterator but starting at the end of the slice.

Panics

Panics if chunk_size is 0.

auto concat() const& -> auto
requires
sus::collections::Concat<T>

Flattens and concatenates the items in the Slice.

The items of type T are flattened into a collection of type T::ConcatOutputType. This method is only supported for types that satisfy the sus::collections::Concat<T> concept.

Slice itself satisfies Concat, with its output being Vec, so that a Slice of Slice<T>s can be concat() together into a single Vec<T>.

Example

i32 a1[] = {1, 2}, a2[] = {3, 4};
Slice<i32> as[] = {Slice<i32>::from(a1), Slice<i32>::from(a2)};
Vec<i32> v = Slice<Slice<i32>>::from(as).concat();
sus_check(v == Slice<i32>::from({1, 2, 3, 4}));
auto concat_into(sus::collections::Vec<T>& vec) const& -> void
requires
sus::mem::Clone<T>

Concatenates a clone of each element in the slice into vec.

This method exists to satisfy sus::collections::Concat<Slice<T>>, for concat() to append the elements in each Slice onto vec.

auto contains(const T& x) const& -> bool
requires
sus::cmp::Eq<T>

Returns true if the slice contains an element with the given value.

This operation is O(n).

Note that if you have a sorted slice, binary_search() may be faster.

Stops tracking iterator invalidation.

Safety

If the Slice points into a collection and that collection is invalidated, it will no longer be caught. The caller must provide conditions that can ensure the Slice's pointer into the collection will remain valid.

Iterator invalidation tracking also tracks the stability of the collection object itself, not just its contents, which can be overly strict.

This function can be used when the collection's contents will remain valid, but the collection itself may be moved, which would invalidate the tracking and be treated as invalidating the iterator. There is no way to restore tracking.

auto ends_with(const Slice<T>& suffix) const& -> bool
requires
sus::cmp::Eq<T>

Returns true if suffix is a suffix of the slice.

auto first() const& -> Option<const T&>

Returns the first element of the slice, or None if it is empty.

auto get(usize i) const& -> Option<const T&>

Returns a const reference to the element at index i, or None if i is beyond the end of the Slice.

auto get_range(const RangeBounds<usize> auto range) const& -> Option<Slice<T>>

Returns a subslice which contains elements in range, which specifies a start and a length.

The start is the index of the first element to be returned in the subslice, and the length is the number of elements in the output slice. As such, r.get_range(Range(0u, r.len())) returns a slice over the full set of elements in r.

Returns None if the Range would otherwise contain an element that is out of bounds.

auto get_range_unchecked(UnsafeFnMarker, const RangeBounds<usize> auto range) const& -> Slice<T>

Returns a subslice which contains elements in range, which specifies a start and a length.

The start is the index of the first element to be returned in the subslice, and the length is the number of elements in the output slice. As such, r.get_range(Range(0u, r.len())) returns a slice over the full set of elements in r.

Safety

It is possible to specify a Range contains an element that is out of bounds of the Slice, which can result in Undefined Behaviour.

auto get_unchecked(UnsafeFnMarker, usize i) const& -> const T&

Returns a const reference to the element at index i.

Safety

The index i must be inside the bounds of the slice or Undefined Behaviour results. The size of the slice must therefore also have a length of at least 1.

auto into_iter() && -> SliceIter<const T&>

Converts the slice into an iterator that consumes the slice and returns each element in the same order they appear in the slice.

auto is_empty() const& -> bool

Returns true if the slice has a length of 0.

auto iter() const& -> SliceIter<const T&>

Returns an iterator over all the elements in the slice, visited in the same order they appear in the slice. The iterator gives const access to each element.

template <class Sep>
auto join(const Sep& separator) const& -> auto
requires
sus::collections::Join<T, Sep>

Flattens and concatenates the items in the Slice, cloning a separator between each item.

The items of type T are flattened into a collection of type T::JoinOutputType. This method is only supported for types that satisfy the sus::collections::Join<T> concept.

Slice itself satisfies Join, with its output being Vec, so that a Slice of Slice<T>s can be join() together into a single Vec<T>.

Example

i32 a1[] = {1, 2}, a2[] = {3, 4}, asep[] = {10, 11, 12};
Slice<i32> as[] = {Slice<i32>::from(a1), Slice<i32>::from(a2)};

// Join slices with a slice between.
Vec<i32> v = Slice<Slice<i32>>::from(as).join(Slice<i32>::from(asep));
sus_check(v == sus::Vec<i32>(1, 2, 10, 11, 12, 3, 4));

// Join slices with a single item between.
Vec<i32> v2 = Slice<Slice<i32>>::from(as).join(99);
sus_check(v2 == sus::Vec<i32>(1, 2, 99, 3, 4));
auto join_into(sus::collections::Vec<T>& vec) const& -> void
requires
sus::mem::Clone<T>

Joins a clone of each element in the slice into vec.

This method exists to satisfy sus::collections::Join<Slice<T>, U>, for join() to append the elements in each Slice onto vec.

auto last() const& -> Option<const T&>

Returns the last element of the slice, or None if it is empty.

auto len() const& -> usize

Returns the number of elements in the slice.

auto partition_point(FnMut<bool(const T&)> auto pred) const& -> usize

Returns the index of the partition point according to the given predicate (the index of the first element of the second partition).

The slice is assumed to be partitioned according to the given predicate. This means that all elements for which the predicate returns true are at the start of the slice and all elements for which the predicate returns false are at the end. For example, [7, 15, 3, 5, 4, 12, 6] is partitioned under the predicate x % 2 != 0 (all odd numbers are at the start, all even at the end).

If this slice is not partitioned, the returned result is unspecified and meaningless, as this method performs a kind of binary search.

See also binary_search(), binary_search_by(), and binary_search_by_key().

auto rchunks(usize chunk_size) const& -> RChunks<T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the end of the slice.

The chunks are slices and do not overlap. If chunk_size does not divide the length of the slice, then the last chunk will not have length chunk_size.

See rchunks_exact() for a variant of this iterator that returns chunks of always exactly chunk_size elements, and chunks() for the same iterator but starting at the beginning of the slice.

Panics

Panics if chunk_size is 0.

auto rchunks_exact(usize chunk_size) const& -> RChunksExact<T>

Returns an iterator over chunk_size elements of the slice at a time, starting at the end of the slice.

The chunks are slices and do not overlap. If chunk_size does not divide the length of the slice, then the last up to chunk_size-1 elements will be omitted and can be retrieved from the remainder() function of the iterator.

TODO: Verify if: Due to each chunk having exactly chunk_size elements, the compiler can often optimize the resulting code better than in the case of rchunks().

See rchunks() for a variant of this iterator that also returns the remainder as a smaller chunk, and chunks_exact() for the same iterator but starting at the beginning of the slice.

Panics

Panics if chunk_size is 0.

auto repeat(sus::usize n) const& -> sus::collections::Vec<T>
requires
sus::mem::TrivialCopy<T>

Creates a vector by copying a slice n times.

Panics

This function will panic if the capacity would become larger than isize::MAX.

Examples

auto v = sus::Vec<i32>(1, 2);
sus_check(v[".."_r].repeat(3) == sus::vec(1, 2, 1, 2, 1, 2).construct<i32>());
template <class Pred>
auto rsplit(Pred pred) const& -> RSplit<T, Pred>
requires
sus::fn::FnMut<Pred, _Bool (const T &)>

Returns an iterator over subslices separated by elements that match pred, starting at the end of the slice and working backwards. The matched element is not contained in the subslices.

As with split(), if the first or last element is matched, an empty slice will be the first (or last) item returned by the iterator.

template <class Pred>
auto rsplitn(sus::usize n, Pred pred) const& -> RSplitN<T, Pred>
requires
sus::fn::FnMut<Pred, _Bool (const T &)>

Returns an iterator over subslices separated by elements that match pred limited to returning at most n items. This starts at the end of the slice and works backwards. The matched element is not contained in the subslices.

The last element returned, if any, will contain the remainder of the slice.

template <class Pred>
auto split(Pred pred) const& -> Split<T, Pred>
requires
sus::fn::FnMut<Pred, _Bool (const T &)>

Returns an iterator over subslices separated by elements that match pred. The matched element is not contained in the subslices.

If the first element is matched, an empty slice will be the first item returned by the iterator. Similarly, if the last element in the slice is matched, an empty slice will be the last item returned by the iterator.

auto split_at(usize mid) const& -> Tuple<Slice<T>, Slice<T>>

Divides one slice into two at an index.

The first will contain all indices from [0, mid) (excluding the index mid itself) and the second will contain all indices from [mid, len()) (excluding the index len() itself).

Panics

Panics if mid > len().

Divides one slice into two at an index, without doing bounds checking.

The first will contain all indices from [0, mid) (excluding the index mid itself) and the second will contain all indices from [mid, len) (excluding the index len itself).

For a safe alternative see split_at().

Safety

Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used. The caller has to ensure that 0 <= mid <= len().

auto split_first() const& -> Option<Tuple<const T&, Slice<T>>>

Returns the first and all the rest of the elements of the slice, or None if it is empty.

template <class Pred>
auto split_inclusive(Pred pred) const& -> SplitInclusive<T, Pred>
requires
sus::fn::FnMut<Pred, _Bool (const T &)>

Returns an iterator over subslices separated by elements that match pred. The matched element is contained in the end of the previous subslice as a terminator.

If the last element of the slice is matched, that element will be considered the terminator of the preceding slice. That slice will be the last item returned by the iterator.

auto split_last() const& -> Option<Tuple<const T&, Slice<T>>>

Returns the last and all the rest of the elements of the slice, or None if it is empty.

template <class Pred>
auto splitn(sus::usize n, Pred pred) const& -> SplitN<T, Pred>
requires
sus::fn::FnMut<Pred, _Bool (const T &)>

Returns an iterator over subslices separated by elements that match pred, limited to returning at most n items. The matched element is not contained in the subslices.

The last element returned, if any, will contain the remainder of the slice.

auto starts_with(const Slice<T>& needle) const& -> bool
requires
sus::cmp::Eq<T>

Returns true if needle is a prefix of the slice.

auto strip_prefix(const Slice<T>& prefix) const& -> Option<Slice<T>>
requires
sus::cmp::Eq<T>

Returns a subslice with the prefix removed.

If the slice starts with prefix, returns the subslice after the prefix, wrapped in Some. If prefix is empty, simply returns the original slice.

If the slice does not start with prefix, returns None.

TODO: Accept a SlicePattern<T> concept instead of just a Slice<T>.

auto strip_suffix(const Slice<T>& suffix) const& -> Option<Slice<T>>
requires
sus::cmp::Eq<T>

Returns a subslice with the suffix removed.

If the slice ends with suffix, returns the subslice before the suffix, wrapped in Some. If suffix is empty, simply returns the original slice.

If the slice does not end with suffix, returns None.

auto subrange(sus::usize start) const& -> Slice<T>
auto subrange(sus::usize start, sus::usize end) const& -> Slice<T>

Returns a subslice which contains elements in the range which is specified by a start and an end. This is an alias for the subscript operator with a RangeBounds argument, but without the need to construct a RangeBounds.

The returned slice contains all indices in start <= x < end. It is empty if start >= end.

NOTE: This is different from std::span::subspan which uses a start and a length. Instead, this matches the construction of a Range in C++ and a Range in Rust.

Panics

If the Range would otherwise contain an element that is out of bounds, the function will panic.

auto to_vec() const& -> sus::collections::Vec<T>
requires
sus::mem::Clone<T>

Constructs a Vec<T> by cloning each value in the Slice.

The caller can choose traits for the Vec by specifying the trait type.

auto windows(sus::usize size) const& -> Windows<T>

Returns an iterator over all contiguous windows of length size. The windows overlap. If the slice is shorter than size, the iterator returns no values.

Panics

Panics if size is 0.

Operators

auto operator[](sus::usize i) const& -> const T&

Returns a reference to the element at position i in the Slice.

Panics

If the index i is beyond the end of the slice, the function will panic.

auto operator[](const RangeBounds<sus::usize> auto range) const& -> Slice<T>

Returns a subslice which contains elements in range, which specifies a start and an end.

The start is the index of the first element to be returned in the subslice, and the end one past the last element in the output slice. As such, r.get_range(Range(0u, r.len())) returns a slice over the full set of elements in r.

Panics

If the Range would otherwise contain an element that is out of bounds, the function will panic.