32namespace nda::detail {
35 struct bound_check_worker {
37 long const *lengths{};
40 uint32_t error_code = 0;
43 int ellipsis_loss = 0;
49 void check_current_dim(
long idx) {
50 if ((idx < 0) or (idx >= lengths[N])) { error_code += 1ul << N; }
55 void check_current_dim(range
const &r) {
57 auto first_idx = r.first();
58 auto last_idx = first_idx + (r.size() - 1) * r.step();
59 if (first_idx < 0 or first_idx >= lengths[N] or last_idx < 0 or last_idx >= lengths[N]) error_code += 1ul << N;
65 void check_current_dim(range::all_t) { ++N; }
68 void check_current_dim(ellipsis) { N += ellipsis_loss + 1; }
71 void accumulate_error_msg(std::stringstream &fs,
long idx) {
72 if (error_code & (1ull << N)) fs <<
"Argument " << N <<
" = " << idx <<
" is not within [0," << lengths[N] <<
"[.\n";
77 void accumulate_error_msg(std::stringstream &fs, range
const &r) {
78 if (error_code & (1ull << N)) fs <<
"Argument " << N <<
" = " << r <<
" is not within [0," << lengths[N] <<
"[.\n";
83 void accumulate_error_msg(std::stringstream &, range::all_t) { ++N; }
86 void accumulate_error_msg(std::stringstream &, ellipsis) { N += ellipsis_loss + 1; }
105 template <
typename... Args>
108 detail::bound_check_worker w{lengths};
111 w.ellipsis_loss = rank -
sizeof...(Args);
114 (w.check_current_dim(args), ...);
117 if (!w.error_code)
return;
121 std::stringstream fs;
122 (w.accumulate_error_msg(fs, args), ...);
123 throw std::runtime_error(
"Index/Range out of bounds:\n" + fs.str());
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.
Includes the itertools header and provides some additional utilities.