|
Stratax 0.3.1
|
Version: v0.2.0
Status: Complete
Header: include/stratax/indexing/Slicing.hpp
The slicing API copies strided selections from Vector, Matrix, and Tensor containers into new owning containers. It resolves raw stratax::core::Slice bounds against concrete dimension extents, supports positive and negative steps, clamps bounds, and preserves traversal order.
The slicing module is responsible for:
It does not provide non-owning views, omitted-bound syntax, broadcasting, or advanced gather indexing.
size_type represents extents, output counts, and flat offsets. difference_type represents normalized signed positions and steps.
The internal detail::normalize_slice helper converts one raw Slice into:
Normalization is O(1):
difference_type::max() is rejected.[0, extent].[-1, extent - 1].-1 remains the reverse-range sentinel instead of being translated.For example, Slice{-1, -1, -1} selects a complete dimension in reverse order.
The slice is resolved against vec.size(). Selected values are copied into a new rank-one Vector in traversal order.
Throws:
Exceptions::IndexError("Vector slice out of bounds.") if the source extent cannot be represented by difference_typestd::bad_alloc if result allocation failsComplexity: O(k), where k is the result size.
Row and column ranges are resolved independently. The returned Matrix has shape {resolved_rows.size, resolved_cols.size} and owns a row-major copy of the selected rectangle.
Throws:
Exceptions::IndexError("Matrix row slice out of bounds.") if the row extent cannot be representedExceptions::IndexError("Matrix column slice out of bounds.") if the column extent cannot be representedstd::bad_alloc if result allocation failsComplexity: O(result.rows() * result.cols()).
Every variadic argument must be exactly core::Slice, enforced with a compile-time assertion. Exactly one Slice must be supplied per tensor dimension.
Each dimension is normalized independently. Its selected count becomes the corresponding output dimension, and selected values are copied into the result in row-major order.
Throws:
Exceptions::IndexError("Tensor slice rank must match tensor rank.") if the number of Slice arguments differs from tensor.rank()Exceptions::IndexError("Tensor slice out of bounds.") if a dimension extent cannot be represented by difference_typeExceptions::DimensionError("Tensor slice offset overflow.") if checked source-offset arithmetic overflowsExceptions::DimensionError if output shape or stride arithmetic overflowsComplexity: O(result.size() * tensor.rank()).
An empty selected dimension returns an empty Tensor with the fully resolved shape. A rank-zero Tensor can be sliced by supplying no Slice arguments.
This overload performs the same normalization and copy operation but accepts a runtime-sized vector of Slice objects.
Throws:
Exceptions::DimensionError("Slice rank must match tensor rank.") if slices.size() != tensor.rank()Exceptions::IndexError("Tensor slice out of bounds.") if a dimension extent cannot be represented by difference_typeExceptions::DimensionError("Tensor slice offset overflow.") if checked source-offset arithmetic overflowsExceptions::DimensionError if output shape or stride arithmetic overflowsComplexity: O(result.size() * tensor.rank()).
For equivalent ranges, this overload produces the same shape and values as the variadic overload.
Every overload returns an independent owning container. Modifying a result does not modify the source, and result storage does not alias source storage.
Out-of-range bounds are normally clamped rather than rejected. Directionally empty ranges and zero-sized source dimensions produce correctly shaped empty containers without entering the element-copy loops.
| Operation | Complexity |
|---|---|
| Normalize one Slice | O(1) |
| Vector slicing | O(result.size()) |
| Matrix slicing | O(result.rows() * result.cols()) |
| Tensor slicing | O(result.size() * tensor.rank()) |
All overloads allocate storage proportional to the number of selected elements, plus output shape/stride metadata.
Slicing currently materializes owning copies. This keeps lifetime and mutation semantics straightforward but makes even contiguous selections O(n).
Both Tensor overloads throw RankError when the number of slices does not match the tensor rank.