25#ifdef NDA_ENFORCE_BOUNDCHECK
33 template <
int Rank, u
int64_t StaticExtents, u
int64_t Str
ideOrder, layout_prop_e LayoutProp>
39namespace nda::slice_static {
83 template <
typename... Args,
size_t... Is>
84 constexpr int ellipsis_position_impl(std::index_sequence<Is...>) {
86 int r = ((std::is_same_v<Args, ellipsis> ? int(Is) + 1 : 0) + ...);
87 return (r == 0 ? 128 : r - 1);
91 template <
typename... Args>
92 constexpr int ellipsis_position() {
93 return detail::ellipsis_position_impl<Args...>(std::make_index_sequence<
sizeof...(Args)>{});
97 constexpr int q_of_n(
int n,
int e_pos,
int e_len) {
99 if (n < e_pos)
return n;
102 if (n < (e_pos + e_len))
return e_pos;
105 return n - (e_len - 1);
109 template <
int N,
int P,
size_t Q>
110 constexpr std::array<int, P> n_of_p_map(std::array<bool, Q>
const &args_is_range,
int e_pos,
int e_len) {
113 for (
int n = 0, p = 0; n < N; ++n) {
115 int q = q_of_n(n, e_pos, e_len);
117 if (args_is_range[q]) result[p++] = n;
123 template <
int N,
int P,
size_t Q>
124 constexpr std::array<int, P> q_of_p_map(std::array<bool, Q>
const &args_is_range,
int e_pos,
int e_len) {
128 for (
int n = 0; n < N; ++n) {
130 int q = q_of_n(n, e_pos, e_len);
132 if (args_is_range[q]) result[p++] = q;
138 template <
size_t N,
size_t P>
139 constexpr std::array<int, N> p_of_n_map(std::array<int, P>
const &n_of_p) {
141 for (
size_t p = 0; p < P; ++p) result[n_of_p[p]] = p;
146 template <
size_t P,
size_t N>
147 constexpr std::array<int, P> slice_stride_order(std::array<int, N>
const &orig_stride_order, std::array<int, P>
const &n_of_p) {
149 auto p_of_n = p_of_n_map<N>(n_of_p);
150 for (
int i = 0, ip = 0; i < N; ++i) {
152 int n = orig_stride_order[i];
156 if (p != -1) result[ip++] = p;
162 template <
size_t Q,
size_t N>
163 constexpr layout_prop_e slice_layout_prop(
int P,
bool has_only_rangeall_and_long, std::array<bool, Q>
const &args_is_rangeall,
164 std::array<int, N>
const &orig_stride_order,
layout_prop_e orig_layout_prop,
int e_pos,
int e_len) {
166 if (not has_only_rangeall_and_long) {
169 return layout_prop_e::strided_1d;
172 return layout_prop_e::none;
177 int n_rangeall_blocks = 0;
178 bool previous_arg_is_rangeall =
false;
179 for (
int i = 0; i < N; ++i) {
180 int q = q_of_n(orig_stride_order[i], e_pos, e_len);
181 bool arg_is_rangeall = args_is_rangeall[q];
182 if (arg_is_rangeall and (not previous_arg_is_rangeall)) ++n_rangeall_blocks;
183 previous_arg_is_rangeall = arg_is_rangeall;
185 bool rangeall_are_grouped_in_memory = (n_rangeall_blocks <= 1);
186 bool last_is_rangeall = previous_arg_is_rangeall;
189 if (
has_contiguous(orig_layout_prop) and rangeall_are_grouped_in_memory and last_is_rangeall)
return layout_prop_e::contiguous;
190 if (
has_strided_1d(orig_layout_prop) and rangeall_are_grouped_in_memory)
return layout_prop_e::strided_1d;
193 return layout_prop_e::none;
198 FORCEINLINE
long get_offset(
long idx,
long stride) {
return idx * stride; }
202 FORCEINLINE
long get_offset(range
const &rg,
long stride) {
return rg.first() * stride; }
206 FORCEINLINE
long get_offset(range::all_t,
long) {
return 0; }
209 FORCEINLINE
long get_length(range
const &rg,
long original_len) {
210 auto last = (rg.last() == -1 and rg.step() > 0) ? original_len : rg.last();
211 return range(rg.first(), last, rg.step()).size();
216 FORCEINLINE
long get_length(range::all_t,
long original_len) {
return original_len; }
219 FORCEINLINE
long get_stride(range
const &rg,
long original_str) {
return original_str * rg.step(); }
223 FORCEINLINE
long get_stride(range::all_t,
long original_str) {
return original_str; }
226 template <
size_t... Ps,
size_t... Ns,
typename IdxMap,
typename... Args>
227 FORCEINLINE
auto slice_idx_map_impl(std::index_sequence<Ps...>, std::index_sequence<Ns...>, IdxMap
const &idxm, Args
const &...args) {
229#ifdef NDA_ENFORCE_BOUNDCHECK
233 static_assert(IdxMap::rank() ==
sizeof...(Ns),
"Internal error in slice_idx_map_impl: Rank and length of index sequence do not match");
237 static constexpr int N =
sizeof...(Ns);
238 static constexpr int P =
sizeof...(Ps);
239 static constexpr int Q =
sizeof...(Args);
240 static constexpr int e_len = N - Q + 1;
241 static constexpr int e_pos = ellipsis_position<Args...>();
244 static constexpr std::array<bool, Q> args_is_range{(std::is_same_v<Args, range> or std::is_base_of_v<range::all_t, Args>)...};
247 static constexpr std::array<bool, Q> args_is_rangeall{(std::is_base_of_v<range::all_t, Args>)...};
250 static constexpr std::array<int, P> n_of_p = n_of_p_map<N, P>(args_is_range, e_pos, e_len);
253 static constexpr std::array<int, P> q_of_p = q_of_p_map<N, P>(args_is_range, e_pos, e_len);
256 static_assert(n_of_p.size() == P,
"Internal error in slice_idx_map_impl: Size of the mapping n_of_p and P do not match");
257 static_assert(q_of_p.size() == P,
"Internal error in slice_idx_map_impl: Size of the mapping q_of_p and P do not match");
260 auto argstie = std::tie(args...);
263 long offset = (get_offset(std::get<q_of_n(Ns, e_pos, e_len)>(argstie), std::get<Ns>(idxm.strides())) + ... + 0);
266 std::array<long, P> len{get_length(std::get<q_of_p[Ps]>(argstie), std::get<n_of_p[Ps]>(idxm.lengths()))...};
267 std::array<long, P> str{get_stride(std::get<q_of_p[Ps]>(argstie), std::get<n_of_p[Ps]>(idxm.strides()))...};
271 static constexpr std::array<int, P> new_static_extents{(args_is_rangeall[q_of_p[Ps]] ? IdxMap::static_extents[n_of_p[Ps]] : 0)...};
274 static constexpr std::array<int, P> new_stride_order = slice_stride_order(IdxMap::stride_order, n_of_p);
277 static constexpr bool has_only_rangeall_and_long = ((std::is_constructible_v<long, Args> or std::is_base_of_v<range::all_t, Args>)and...);
279 slice_layout_prop(P, has_only_rangeall_and_long, args_is_rangeall, IdxMap::stride_order, IdxMap::layout_prop, e_pos, e_len);
282 static constexpr uint64_t new_static_extents_encoded =
encode(new_static_extents);
283 static constexpr uint64_t new_stride_order_encoded =
encode(new_stride_order);
284 return std::make_pair(offset, idx_map<P, new_static_extents_encoded, new_stride_order_encoded, li>{len, str});
313 template <
int R, uint64_t SE, uint64_t SO,
layout_prop_e LP,
typename... Args>
316 static constexpr int n_args_ellipsis = ((std::is_same_v<Args, ellipsis>)+...);
317 static constexpr int n_args_long = (std::is_constructible_v<long, Args> + ...);
320 static_assert(n_args_ellipsis <= 1,
"Error in nda::slice_static::slice_idx_map: At most one ellipsis argument is allowed");
321 static_assert((
sizeof...(Args) <= R + 1),
"Error in nda::slice_static::slice_idx_map: Incorrect number of arguments");
322 static_assert((n_args_ellipsis == 1) or (
sizeof...(Args) == R),
"Error in nda::slice_static::slice_idx_map: Incorrect number of arguments");
324 return detail::slice_idx_map_impl(std::make_index_sequence<R - n_args_long>{}, std::make_index_sequence<R>{}, idxm, args...);
Provides utility functions for std::array.
Provides a way to check the bounds when accessing elements/slices of an array or a view.
Layout that specifies how to map multi-dimensional indices to a linear/flat index.
__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 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 uint64_t encode(std::array< int, N > const &a)
Encode a std::array<int, N> in a uint64_t.
constexpr std::array< T, R > make_initialized_array(T v)
Create a new std::array object initialized with a specific value.
Macros used in the nda library.
Includes the itertools header and provides some additional utilities.
Provides type traits for the nda library.