89 template <
int Rank, u
int64_t StaticExtents, u
int64_t Str
ideOrder, layout_prop_e LayoutProp>
91 static_assert(Rank < 16,
"Error in nda::idx_map: Rank must be < 16");
92 static_assert((StrideOrder != 0) or (Rank == 1),
"Error in nda::idx_map: StrideOrder can only be zero for 1D arrays");
95 std::array<long, Rank> len{};
98 std::array<long, Rank> str{};
120 template <
typename T>
124 template <
typename T>
126 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>;
132 for (
int u = 0; u < Rank; ++u) r += (
static_extents[u] == 0 ? 1 : 0);
141 static constexpr int rank() noexcept {
return Rank; }
147 [[nodiscard]]
long size() const noexcept {
return std::accumulate(len.cbegin(), len.cend(), 1L, std::multiplies<>{}); }
165 [[nodiscard]] std::array<long, Rank>
const &
lengths() const noexcept {
return len; }
171 [[nodiscard]] std::array<long, Rank>
const &
strides() const noexcept {
return str; }
190 if (s == 0)
return true;
198 [[nodiscard]]
bool has_positive_strides() const noexcept {
return (*std::min_element(str.cbegin(), str.cend()) >= 0); }
212 if (s == 0)
return true;
238 template <std::
integral Int>
240 auto dims_to_check = std::vector<int>{};
241 dims_to_check.reserve(Rank);
243 if (lenptr[dim] > 1) dims_to_check.push_back(dim);
244 for (
int n = 1; n < dims_to_check.size(); ++n)
245 if (std::abs(strptr[dims_to_check[n - 1]]) < std::abs(strptr[dims_to_check[n]]))
return false;
258 void compute_strides_contiguous() {
260 for (
int v =
rank() - 1; v >= 0; --v) {
261 int u = stride_order[v];
265 ENSURES(s ==
size());
269 void assert_static_extents_and_len_are_compatible()
const {
270#ifdef NDA_ENFORCE_BOUNDCHECK
273 for (
int u = 0; u < Rank; ++u)
282 static constexpr bool check_stride_order =
true;
284 static constexpr bool check_stride_order =
false;
288 static std::array<long, Rank> merge_static_and_dynamic_extents(std::array<long, n_dynamic_extents>
const &dynamic_extents) {
289 std::array<long, Rank> extents;
308 compute_strides_contiguous();
318 template <layout_prop_e LP>
326 EXPECTS_WITH_MESSAGE(idxm.is_contiguous(),
"Error in nda::idx_map: Constructing a contiguous from a non-contiguous layout");
329 EXPECTS_WITH_MESSAGE(idxm.is_strided_1d(),
"Error in nda::idx_map: Constructing a strided_1d from a non-strided_1d layout");
341 template <u
int64_t SE, layout_prop_e LP>
349 EXPECTS_WITH_MESSAGE(idxm.is_contiguous(),
"Error in nda::idx_map: Constructing a contiguous from a non-contiguous layout");
352 EXPECTS_WITH_MESSAGE(idxm.is_strided_1d(),
"Error in nda::idx_map: Constructing a strided_1d from a non-strided_1d layout");
357 assert_static_extents_and_len_are_compatible();
367 std::array<long, Rank>
const &
strides)
noexcept(!check_stride_order)
369 EXPECTS(std::all_of(shape.cbegin(), shape.cend(), [](
auto const &i) { return i >= 0; }));
370 if constexpr (check_stride_order) {
371 if (not
is_stride_order_valid())
throw std::runtime_error(
"Error in nda::idx_map: Incompatible strides, shape and stride order");
381 template <std::
integral Int =
long>
383 EXPECTS(std::all_of(shape.cbegin(), shape.cend(), [](
auto const &i) { return i >= 0; }));
384 assert_static_extents_and_len_are_compatible();
385 compute_strides_contiguous();
396 idx_map(std::array<long, n_dynamic_extents>
const &shape)
noexcept
398 :
idx_map(merge_static_and_dynamic_extents(shape)) {}
409 template <u
int64_t SE, u
int64_t SO, layout_prop_e LP>
413 static_assert((
stride_order_encoded == SO),
"Error in nda::idx_map: Incompatible stride orders");
425 static_assert(R == Rank,
"Error in nda::idx_map: Incompatible ranks");
442 template <
bool skip_str
ide, auto I>
443 [[nodiscard]] FORCEINLINE
long myget(
ellipsis)
const noexcept {
449 template <
bool skip_str
ide, auto I>
450 [[nodiscard]] FORCEINLINE
long myget(
long arg)
const noexcept {
451 if constexpr (skip_stride and (I == stride_order[Rank - 1])) {
456 return arg * std::get<I>(str);
464 template <
typename... Args,
size_t... Is>
465 [[nodiscard]] FORCEINLINE
long call_impl(std::index_sequence<Is...>, Args... args)
const noexcept {
467 static constexpr int e_pos = ((std::is_same_v<Args, ellipsis> ? int(Is) + 1 : 0) + ...) - 1;
469 if constexpr (e_pos == -1) {
471 if constexpr (smallest_stride_is_one) {
473 return (myget<true, Is>(
static_cast<long>(args)) + ...);
476 return ((args * std::get<Is>(str)) + ...);
480 return (myget<smallest_stride_is_one, (Is < e_pos ? Is : Is - 1)>(args) + ...);
503 template <
typename... Args>
505#ifdef NDA_ENFORCE_BOUNDCHECK
511 return call_impl(std::make_index_sequence<
sizeof...(Args)>{}, args...);
535 std::array<long, Rank>
to_idx(
long lin_idx)
const {
537 std::array<long, Rank> residues;
538 residues[0] = lin_idx;
539 for (
auto i : range(1, Rank)) { residues[i] = residues[i - 1] % str[
stride_order[i - 1]]; }
542 std::array<long, Rank> idx;
543 idx[Rank - 1] = residues[Rank - 1] / str[
stride_order[Rank - 1]];
544 for (
auto i : range(Rank - 2, -1, -1)) { idx[i] = (residues[i] - residues[i + 1]) / str[
stride_order[i]]; }
561 template <
typename... Args>
562 auto slice(Args
const &...args)
const {
576 template <
int R, u
int64_t SE, u
int64_t SO, layout_prop_e LP>
578 return (Rank == R and len == rhs.
lengths() and str == rhs.
strides());
595 template <u
int64_t Permutation>
638 static constexpr std::array<int, Rank> permu =
decode<Rank>(Permutation);
__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
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
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
static constexpr uint64_t stride_order_encoded
static constexpr int rank() noexcept
Get the rank of the map.
static constexpr std::array< int, Rank > 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
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
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
static constexpr uint64_t static_extents_encoded
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.