19namespace nda::detail {
22 struct bound_check_worker {
24 long const *lengths{};
27 uint32_t error_code = 0;
30 int ellipsis_loss = 0;
36 void check_current_dim(
long idx) {
37 if ((idx < 0) or (idx >= lengths[N])) { error_code += 1ul << N; }
42 void check_current_dim(range
const &r) {
44 auto first_idx = r.first();
45 auto last_idx = first_idx + (r.size() - 1) * r.step();
46 if (first_idx < 0 or first_idx >= lengths[N] or last_idx < 0 or last_idx >= lengths[N]) error_code += 1ul << N;
52 void check_current_dim(range::all_t) { ++N; }
55 void check_current_dim(ellipsis) { N += ellipsis_loss + 1; }
58 void accumulate_error_msg(std::stringstream &fs,
long idx) {
59 if (error_code & (1ull << N)) fs <<
"Argument " << N <<
" = " << idx <<
" is not within [0," << lengths[N] <<
"[.\n";
64 void accumulate_error_msg(std::stringstream &fs, range
const &r) {
65 if (error_code & (1ull << N)) fs <<
"Argument " << N <<
" = " << r <<
" is not within [0," << lengths[N] <<
"[.\n";
70 void accumulate_error_msg(std::stringstream &, range::all_t) { ++N; }
73 void accumulate_error_msg(std::stringstream &, ellipsis) { N += ellipsis_loss + 1; }
92 template <
typename... Args>
95 detail::bound_check_worker w{lengths};
98 w.ellipsis_loss = rank -
sizeof...(Args);
101 (w.check_current_dim(args), ...);
104 if (!w.error_code)
return;
108 std::stringstream fs;
109 (w.accumulate_error_msg(fs, args), ...);
110 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.