8#include <stratax/containers/Matrix.hpp>
9#include <stratax/containers/Tensor.hpp>
10#include <stratax/containers/Vector.hpp>
11#include <stratax/exceptions/Exceptions.hpp>
12#include <stratax/core/Shape.hpp>
13#include <stratax/core/Slice.hpp>
14#include <stratax/core/validation/Validation.hpp>
24namespace stratax::indexing {
27using size_type = std::size_t;
29using difference_type = std::ptrdiff_t;
68 if (extent >
static_cast<size_type
>(std::numeric_limits<difference_type>::max()))
73 const difference_type n =
static_cast<difference_type
>(extent);
74 difference_type start = slice.
start();
75 difference_type stop = slice.stop();
76 const difference_type step = slice.step();
89 start = std::clamp(start, difference_type{0}, n);
90 stop = std::clamp(stop, difference_type{0}, n);
97 const difference_type distance = stop - start;
98 const size_type count =
static_cast<size_type
>((distance + step - 1) / step);
106 if (stop < 0 && stop != -1)
111 start = std::clamp(start, difference_type{-1}, n - 1);
112 stop = std::clamp(stop, difference_type{-1}, n - 1);
119 const difference_type stride = -step;
120 const difference_type distance = start - stop;
121 const size_type count =
static_cast<size_type
>((distance + stride - 1) / stride);
142stratax::container::Vector<T>
144 const stratax::container::Vector<T>& vec,
145 const stratax::core::Slice& slice)
147 const auto resolved =
148 detail::normalize_slice(
151 "Vector slice out of bounds.");
153 stratax::container::Vector<T> result(resolved.size);
155 difference_type source = resolved.start;
157 for (size_type i = 0; i < result.size(); ++i)
159 result[i] = vec[
static_cast<size_type
>(source)];
160 source += resolved.step;
182stratax::container::Matrix<T>
184 const stratax::container::Matrix<T>& mat,
185 const stratax::core::Slice& rows,
186 const stratax::core::Slice& cols
189 const auto resolved_rows = detail::normalize_slice(
192 "Matrix row slice out of bounds.");
193 const auto resolved_cols = detail::normalize_slice(
196 "Matrix column slice out of bounds.");
198 stratax::container::Matrix<T> result(resolved_rows.size, resolved_cols.size);
200 difference_type source_row = resolved_rows.start;
201 for (size_type out_row = 0; out_row < result.rows(); ++out_row)
203 difference_type source_col = resolved_cols.start;
204 for (size_type out_col = 0; out_col < result.cols(); ++out_col)
206 result(out_row, out_col) = mat(
207 static_cast<size_type
>(source_row),
208 static_cast<size_type
>(source_col));
209 source_col += resolved_cols.step;
211 source_row += resolved_rows.step;
235template<
typename T,
typename... Slices>
236stratax::container::Tensor<T>
238 const stratax::container::Tensor<T>& tensor,
243 (std::is_same_v<Slices, stratax::core::Slice> && ...),
244 "All arguments must be Slice."
247 std::array<stratax::core::Slice,
sizeof...(Slices)> ranges{slices...};
249 if (ranges.size() != tensor.
rank())
251 throw Exceptions::IndexError(
252 "Tensor slice rank must match tensor rank.");
255 std::array<stratax::indexing::detail::ResolvedSlice,
sizeof...(Slices)> resolved{};
256 std::array<size_type,
sizeof...(Slices)> out_dims{};
257 for (size_type dim = 0; dim < ranges.size(); ++dim)
259 resolved[dim] = detail::normalize_slice(
262 "Tensor slice out of bounds.");
263 out_dims[dim] = resolved[dim].size;
266 const auto result_shape = stratax::core::Shape(
267 std::vector<size_type>(out_dims.begin(), out_dims.end()));
268 stratax::container::Tensor<T> result(result_shape);
269 const stratax::core::Shape result_strides = result_shape.strides();
270 const auto& tensor_strides = tensor.
strides();
277 for (size_type flat = 0; flat < result.size(); ++flat)
279 size_type remainder = flat;
280 size_type source_offset = 0;
282 for (size_type dim = 0; dim < resolved.size(); ++dim)
284 const size_type index = remainder / result_strides[dim];
285 remainder %= result_strides[dim];
287 const difference_type source_index =
288 resolved[dim].start +
static_cast<difference_type
>(index) * resolved[dim].step;
289 const size_type term =
290 stratax::core::validation::checked_multiply(
291 static_cast<size_type
>(source_index),
293 "Tensor slice offset overflow.");
295 stratax::core::validation::checked_add(
298 "Tensor slice offset overflow.");
301 result[flat] = tensor[source_offset];
324stratax::container::Tensor<T>
326 const stratax::container::Tensor<T>& tensor,
327 const std::vector<stratax::core::Slice>& slices
330 stratax::core::validation::require_rank(
333 "Slice rank must match tensor rank.");
335 std::vector<detail::ResolvedSlice> resolved(slices.size());
336 std::vector<size_type> out_dims(slices.size());
338 for (size_type dim = 0; dim < slices.size(); ++dim)
340 resolved[dim] = detail::normalize_slice(
343 "Tensor slice out of bounds.");
344 out_dims[dim] = resolved[dim].size;
347 const auto result_shape = stratax::core::Shape(out_dims);
348 stratax::container::Tensor<T> result(result_shape);
355 const stratax::core::Shape result_strides = result_shape.strides();
356 const auto& tensor_strides = tensor.
strides();
358 for (size_type flat = 0; flat < result.size(); ++flat)
360 size_type remainder = flat;
361 size_type source_offset = 0;
363 for (size_type dim = 0; dim < resolved.size(); ++dim)
365 const size_type index = remainder / result_strides[dim];
366 remainder %= result_strides[dim];
368 const difference_type source_index =
369 resolved[dim].start +
static_cast<difference_type
>(index) * resolved[dim].step;
370 const size_type term =
371 stratax::core::validation::checked_multiply(
372 static_cast<size_type
>(source_index),
374 "Tensor slice offset overflow.");
376 stratax::core::validation::checked_add(
379 "Tensor slice offset overflow.");
382 result[flat] = tensor[source_offset];
size_type rows() const noexcept
Returns the number of rows.
size_type cols() const noexcept
Returns the number of columns.
const Shape & shape() const noexcept
Returns the logical shape metadata.
size_type size() const noexcept
Returns the number of stored elements.
size_type rank() const noexcept
Returns the number of logical dimensions.
const Shape & strides() const noexcept
Returns the row-major stride metadata.
Describes a signed, strided half-open index range.
Normalized slice metadata for one concrete dimension.
difference_type step
Signed increment between source indices.
size_type size
Number of selected indices.
difference_type start
First normalized source index.