102 template <
int Rank, u
int64_t StaticExtents, u
int64_t Str
ideOrder, layout_prop_e LayoutProp>
104 static_assert(Rank < 16,
"Error in nda::idx_map: Rank must be < 16");
105 static_assert((StrideOrder != 0) or (Rank == 1),
"Error in nda::idx_map: StrideOrder can only be zero for 1D arrays");
108 std::array<long, Rank> len;
111 std::array<long, Rank> str;
133 template <
typename T>
137 template <
typename T>
139 std::is_same_v<range, T> or std::is_same_v<range::all_t, T> or std::is_same_v<ellipsis, T> or std::is_constructible_v<long, T>;
145 for (
int u = 0; u < Rank; ++u) r += (
static_extents[u] == 0 ? 1 : 0);
154 static constexpr int rank() noexcept {
return Rank; }
160 [[nodiscard]]
long size() const noexcept {
return std::accumulate(len.cbegin(), len.cend(), 1L, std::multiplies<>{}); }
178 [[nodiscard]] std::array<long, Rank>
const &
lengths() const noexcept {
return len; }
184 [[nodiscard]] std::array<long, Rank>
const &
strides() const noexcept {
return str; }
202 if (s == 0)
return true;
203 auto const str_x_len = str * len;
204 return (*std::max_element(str_x_len.cbegin(), str_x_len.cend()) == s);
218 if (s == 0)
return true;
219 auto const str_x_len = str * len;
220 return (*std::max_element(str_x_len.cbegin(), str_x_len.cend()) == s *
min_stride());
243 template <std::
integral Int>
245 auto dims_to_check = std::vector<int>{};
246 dims_to_check.reserve(Rank);
248 if (lenptr[dim] > 1) dims_to_check.push_back(dim);
249 for (
int n = 1; n < dims_to_check.size(); ++n)
250 if (std::abs(strptr[dims_to_check[n - 1]]) < std::abs(strptr[dims_to_check[n]]))
return false;
263 void compute_strides_contiguous() {
265 for (
int v =
rank() - 1; v >= 0; --v) {
270 ENSURES(s ==
size());
274 void assert_static_extents_and_len_are_compatible()
const {
275#ifdef NDA_ENFORCE_BOUNDCHECK
278 for (
int u = 0; u < Rank; ++u)
287 static constexpr bool check_stride_order =
true;
289 static constexpr bool check_stride_order =
false;
293 static std::array<long, Rank> merge_static_and_dynamic_extents(std::array<long, n_dynamic_extents>
const &dynamic_extents) {
294 std::array<long, Rank> extents;
313 compute_strides_contiguous();
315 for (
int u = 0; u < Rank; ++u)
326 template <layout_prop_e LP>
334 EXPECTS_WITH_MESSAGE(idxm.is_contiguous(),
"Error in nda::idx_map: Constructing a contiguous from a non-contiguous layout");
337 EXPECTS_WITH_MESSAGE(idxm.is_strided_1d(),
"Error in nda::idx_map: Constructing a strided_1d from a non-strided_1d layout");
349 template <u
int64_t SE, layout_prop_e LP>
357 EXPECTS_WITH_MESSAGE(idxm.is_contiguous(),
"Error in nda::idx_map: Constructing a contiguous from a non-contiguous layout");
360 EXPECTS_WITH_MESSAGE(idxm.is_strided_1d(),
"Error in nda::idx_map: Constructing a strided_1d from a non-strided_1d layout");
365 assert_static_extents_and_len_are_compatible();
375 std::array<long, Rank>
const &
strides)
noexcept(!check_stride_order)
377 EXPECTS(std::all_of(shape.cbegin(), shape.cend(), [](
auto const &i) { return i >= 0; }));
378 if constexpr (check_stride_order) {
379 if (not
is_stride_order_valid())
throw std::runtime_error(
"Error in nda::idx_map: Incompatible strides, shape and stride order");
389 template <std::
integral Int =
long>
391 EXPECTS(std::all_of(shape.cbegin(), shape.cend(), [](
auto const &i) { return i >= 0; }));
392 assert_static_extents_and_len_are_compatible();
393 compute_strides_contiguous();
404 idx_map(std::array<long, n_dynamic_extents>
const &shape)
noexcept
406 :
idx_map(merge_static_and_dynamic_extents(shape)) {}
417 template <u
int64_t SE, u
int64_t SO, layout_prop_e LP>
421 static_assert((
stride_order_encoded == SO),
"Error in nda::idx_map: Incompatible stride orders");
433 static_assert(R == Rank,
"Error in nda::idx_map: Incompatible ranks");
450 template <
bool skip_str
ide, auto I>
451 [[nodiscard]] FORCEINLINE
long myget(
ellipsis)
const noexcept {
457 template <
bool skip_str
ide, auto I>
458 [[nodiscard]] FORCEINLINE
long myget(
long arg)
const noexcept {
459 if constexpr (skip_stride and (I ==
stride_order[Rank - 1])) {
464 return arg * std::get<I>(str);
472 template <
typename... Args,
size_t... Is>
473 [[nodiscard]] FORCEINLINE
long call_impl(std::index_sequence<Is...>, Args... args)
const noexcept {
475 static constexpr int e_pos = ((std::is_same_v<Args, ellipsis> ? int(Is) + 1 : 0) + ...) - 1;
477 if constexpr (e_pos == -1) {
479 if constexpr (smallest_stride_is_one) {
481 return (myget<true, Is>(
static_cast<long>(args)) + ...);
484 return ((args * std::get<Is>(str)) + ...);
488 return (myget<smallest_stride_is_one, (Is < e_pos ? Is : Is - 1)>(args) + ...);
511 template <
typename... Args>
513#ifdef NDA_ENFORCE_BOUNDCHECK
519 return call_impl(std::make_index_sequence<
sizeof...(Args)>{}, args...);
543 std::array<long, Rank>
to_idx(
long lin_idx)
const {
545 std::array<long, Rank> residues;
546 residues[0] = lin_idx;
547 for (
auto i : range(1, Rank)) { residues[i] = residues[i - 1] % str[
stride_order[i - 1]]; }
550 std::array<long, Rank> idx;
551 idx[Rank - 1] = residues[Rank - 1] / str[
stride_order[Rank - 1]];
552 for (
auto i : range(Rank - 2, -1, -1)) { idx[i] = (residues[i] - residues[i + 1]) / str[
stride_order[i]]; }
569 template <
typename... Args>
570 auto slice(Args
const &...args)
const {
584 template <
int R, u
int64_t SE, u
int64_t SO, layout_prop_e LP>
586 return (Rank == R and len == rhs.
lengths() and str == rhs.
strides());
603 template <u
int64_t Permutation>
646 static constexpr std::array<int, Rank> permu =
decode<Rank>(Permutation);
Layout that specifies how to map multi-dimensional indices to a linear/flat index.
__inline__ long operator()(Args const &...args) const noexcept(true)
Function call operator to map a given multi-dimensional index to a linear index.
static constexpr std::array< int, Rank > stride_order
Decoded stride order.
idx_map(idx_map< Rank, StaticExtents, StrideOrder, LP > const &idxm) noexcept
Construct a new map from an existing map with different layout properties.
static bool is_stride_order_valid(Int *lenptr, Int *strptr)
Check if a given shape and strides are compatible with the stride order.
static constexpr layout_info_t layout_info
Compile-time information about the layout (stride order and layout properties).
idx_map(idx_map &&)=default
Default move constructor.
long size() const noexcept
Get the total number of elements.
long min_stride() const noexcept
Get the value of the smallest stride.
idx_map(std::array< long, n_dynamic_extents > const &shape) noexcept
Construct a new map from an array with its dynamic extents.
auto transpose() const
Create a new map by permuting the indices/dimensions of the current map with a given permutation.
std::array< long, Rank > to_idx(long lin_idx) const
Calculate the multi-dimensional index from a given linear index.
bool is_stride_order_valid() const
Check if the shape and strides of the current map are compatible with its stride order.
idx_map(idx_map< Rank, SE, SO, LP > const &)
Construct a new map from an existing map with a different stride order.
bool operator==(idx_map< R, SE, SO, LP > const &rhs) const
Equal-to operator for two nda::idx_map objects.
static constexpr bool is_stride_order_C()
Is the stride order equal to C-order?
static constexpr int n_dynamic_extents
Number of dynamic dimensions/extents.
static constexpr uint64_t stride_order_encoded
Encoded stride order.
static constexpr int rank() noexcept
Get the rank of the map.
static constexpr std::array< int, Rank > static_extents
Decoded static extents.
bool is_strided_1d() const noexcept
Is the data strided in memory with a constant stride?
static constexpr int argument_is_allowed_for_call_or_slice
Alias template to check if type T can be used to either access a single element or a slice of element...
idx_map(std::array< Int, Rank > const &shape) noexcept
Construct a new map from a given shape and with contiguous strides.
std::array< long, Rank > const & lengths() const noexcept
Get the extents of all dimensions.
auto slice(Args const &...args) const
Get a new nda::idx_map by taking a slice of the current one.
static constexpr bool is_stride_order_Fortran()
Is the stride order equal to Fortran-order?
idx_map(idx_map const &)=default
Default copy constructor.
static constexpr int argument_is_allowed_for_call
Alias template to check if type T can be used to access a single element.
static constexpr long ce_size() noexcept
Get the size known at compile-time.
bool is_contiguous() const noexcept
Is the data contiguous in memory?
idx_map(idx_map< Rank, SE, StrideOrder, LP > const &idxm) noexcept(false)
Construct a new map from an existing map with different layout properties and different static extent...
idx_map(std::array< long, Rank > const &shape, std::array< long, Rank > const &strides) noexcept(!check_stride_order)
Construct a new map from a given shape and strides.
idx_map()
Default constructor.
std::array< long, Rank > const & strides() const noexcept
Get the strides of all dimensions.
idx_map & operator=(idx_map const &)=default
Default copy assignment operator.
static constexpr layout_prop_e layout_prop
Compile-time memory layout properties.
static constexpr uint64_t static_extents_encoded
Encoded static extents.
idx_map & operator=(idx_map &&)=default
Default move assignment operator.
idx_map(std::array< long, R > const &)
Construct a new map with a shape of a different rank.
constexpr uint64_t C_stride_order
C/Row-major stride order.
constexpr uint64_t Fortran_stride_order
Fortran/Column-major stride order.
__inline__ decltype(auto) slice_idx_map(idx_map< R, SE, SO, LP > const &idxm, Args const &...args)
Determine the resulting nda::idx_map when taking a slice of a given nda::idx_map.
constexpr bool layout_property_compatible(layout_prop_e from, layout_prop_e to)
Checks if two layout properties are compatible with each other.
constexpr bool has_contiguous(layout_prop_e lp)
Checks if a layout property has the contiguous property.
constexpr bool has_strided_1d(layout_prop_e lp)
Checks if a layout property has the strided_1d property.
void assert_in_bounds(int rank, long const *lengths, Args const &...args)
Check if the given indices/arguments are within the bounds of an array/view.
constexpr bool has_smallest_stride_is_one(layout_prop_e lp)
Checks if a layout property has the smallest_stride_is_one property.
layout_prop_e
Compile-time guarantees of the memory layout of an array/view.
constexpr std::array< int, N > decode(uint64_t binary_representation)
Decode a uint64_t into a std::array<int, N>.
constexpr std::array< T, N > apply_inverse(std::array< Int, N > const &p, std::array< T, N > const &a)
Apply the inverse of a permutation to a std::array.
constexpr std::array< int, N > identity()
Get the identity permutation.
constexpr uint64_t encode(std::array< int, N > const &a)
Encode a std::array<int, N> in a uint64_t.
constexpr std::array< int, N > reverse_identity()
Get the reverse identity permutation.
constexpr std::array< Int, N > compose(std::array< Int, N > const &p1, std::array< Int, N > const &p2)
Composition of two permutations.
constexpr std::array< T, R > make_std_array(std::array< U, R > const &a)
Convert a std::array with value type U to a std::array with value type T.
Macros used in the nda library.
Provides utilities to work with permutations and to compactly encode/decode std::array objects.
Includes the itertools header and provides some additional utilities.
Provides utilities that determine the resulting nda::idx_map when taking a slice of an nda::idx_map.
Mimics Python's ... syntax.
Stores information about the memory layout and the stride order of an array/view.
Provides type traits for the nda library.