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; }
203 if (s == 0)
return true;
211 [[nodiscard]]
bool has_positive_strides() const noexcept {
return (*std::min_element(str.cbegin(), str.cend()) >= 0); }
225 if (s == 0)
return true;
251 template <std::
integral Int>
253 auto dims_to_check = std::vector<int>{};
254 dims_to_check.reserve(Rank);
256 if (lenptr[dim] > 1) dims_to_check.push_back(dim);
257 for (
int n = 1; n < dims_to_check.size(); ++n)
258 if (std::abs(strptr[dims_to_check[n - 1]]) < std::abs(strptr[dims_to_check[n]]))
return false;
271 void compute_strides_contiguous() {
273 for (
int v =
rank() - 1; v >= 0; --v) {
278 ENSURES(s ==
size());
282 void assert_static_extents_and_len_are_compatible()
const {
283#ifdef NDA_ENFORCE_BOUNDCHECK
286 for (
int u = 0; u < Rank; ++u)
295 static constexpr bool check_stride_order =
true;
297 static constexpr bool check_stride_order =
false;
301 static std::array<long, Rank> merge_static_and_dynamic_extents(std::array<long, n_dynamic_extents>
const &dynamic_extents) {
302 std::array<long, Rank> extents;
321 compute_strides_contiguous();
331 template <layout_prop_e LP>
339 EXPECTS_WITH_MESSAGE(idxm.is_contiguous(),
"Error in nda::idx_map: Constructing a contiguous from a non-contiguous layout");
342 EXPECTS_WITH_MESSAGE(idxm.is_strided_1d(),
"Error in nda::idx_map: Constructing a strided_1d from a non-strided_1d layout");
354 template <u
int64_t SE, layout_prop_e LP>
362 EXPECTS_WITH_MESSAGE(idxm.is_contiguous(),
"Error in nda::idx_map: Constructing a contiguous from a non-contiguous layout");
365 EXPECTS_WITH_MESSAGE(idxm.is_strided_1d(),
"Error in nda::idx_map: Constructing a strided_1d from a non-strided_1d layout");
370 assert_static_extents_and_len_are_compatible();
380 std::array<long, Rank>
const &
strides)
noexcept(!check_stride_order)
382 EXPECTS(std::all_of(shape.cbegin(), shape.cend(), [](
auto const &i) { return i >= 0; }));
383 if constexpr (check_stride_order) {
384 if (not
is_stride_order_valid())
throw std::runtime_error(
"Error in nda::idx_map: Incompatible strides, shape and stride order");
394 template <std::
integral Int =
long>
396 EXPECTS(std::all_of(shape.cbegin(), shape.cend(), [](
auto const &i) { return i >= 0; }));
397 assert_static_extents_and_len_are_compatible();
398 compute_strides_contiguous();
409 idx_map(std::array<long, n_dynamic_extents>
const &shape)
noexcept
411 :
idx_map(merge_static_and_dynamic_extents(shape)) {}
422 template <u
int64_t SE, u
int64_t SO, layout_prop_e LP>
426 static_assert((
stride_order_encoded == SO),
"Error in nda::idx_map: Incompatible stride orders");
438 static_assert(R == Rank,
"Error in nda::idx_map: Incompatible ranks");
455 template <
bool skip_str
ide, auto I>
456 [[nodiscard]] FORCEINLINE
long myget(
ellipsis)
const noexcept {
462 template <
bool skip_str
ide, auto I>
463 [[nodiscard]] FORCEINLINE
long myget(
long arg)
const noexcept {
464 if constexpr (skip_stride and (I ==
stride_order[Rank - 1])) {
469 return arg * std::get<I>(str);
477 template <
typename... Args,
size_t... Is>
478 [[nodiscard]] FORCEINLINE
long call_impl(std::index_sequence<Is...>, Args... args)
const noexcept {
480 static constexpr int e_pos = ((std::is_same_v<Args, ellipsis> ? int(Is) + 1 : 0) + ...) - 1;
482 if constexpr (e_pos == -1) {
484 if constexpr (smallest_stride_is_one) {
486 return (myget<true, Is>(
static_cast<long>(args)) + ...);
489 return ((args * std::get<Is>(str)) + ...);
493 return (myget<smallest_stride_is_one, (Is < e_pos ? Is : Is - 1)>(args) + ...);
516 template <
typename... Args>
518#ifdef NDA_ENFORCE_BOUNDCHECK
524 return call_impl(std::make_index_sequence<
sizeof...(Args)>{}, args...);
548 std::array<long, Rank>
to_idx(
long lin_idx)
const {
550 std::array<long, Rank> residues;
551 residues[0] = lin_idx;
552 for (
auto i : range(1, Rank)) { residues[i] = residues[i - 1] % str[
stride_order[i - 1]]; }
555 std::array<long, Rank> idx;
556 idx[Rank - 1] = residues[Rank - 1] / str[
stride_order[Rank - 1]];
557 for (
auto i : range(Rank - 2, -1, -1)) { idx[i] = (residues[i] - residues[i + 1]) / str[
stride_order[i]]; }
574 template <
typename... Args>
575 auto slice(Args
const &...args)
const {
589 template <
int R, u
int64_t SE, u
int64_t SO, layout_prop_e LP>
591 return (Rank == R and len == rhs.
lengths() and str == rhs.
strides());
608 template <u
int64_t Permutation>
651 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 (positive or negative).
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 has_positive_strides() const noexcept
Are all strides positive?
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.