TRIQS/nda 1.3.0
Multi-dimensional array library for C++
Loading...
Searching...
No Matches
bound_check_worker.hpp
Go to the documentation of this file.
1// Copyright (c) 2018--present, The Simons Foundation
2// This file is part of TRIQS/nda and is licensed under the Apache License, Version 2.0.
3// SPDX-License-Identifier: Apache-2.0
4// See LICENSE in the root of this distribution for details.
5
10
11#pragma once
12
13#include "./range.hpp"
14
15#include <cstdint>
16#include <stdexcept>
17#include <sstream>
18
19namespace nda::detail {
20
21 // Check the bounds when accessing single elements or slices of an array/view.
22 struct bound_check_worker {
23 // Shape of the array/view.
24 long const *lengths{};
25
26 // Error code to store the positions of the arguments which are out of bounds.
27 uint32_t error_code = 0;
28
29 // Number of dimensions that are covered by a given nda::ellipsis.
30 int ellipsis_loss = 0;
31
32 // Current dimension to be checked.
33 int N = 0;
34
35 // Check if the given index is within the bounds of the array/view.
36 void check_current_dim(long idx) {
37 if ((idx < 0) or (idx >= lengths[N])) { error_code += 1ul << N; }
38 ++N;
39 }
40
41 // Check if the given nda::range is within the bounds of the array/view.
42 void check_current_dim(range const &r) {
43 if (r.size() > 0) {
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;
47 }
48 ++N;
49 }
50
51 // Check the bounds when an nda::range::all_t is encountered (no need to check anything).
52 void check_current_dim(range::all_t) { ++N; }
53
54 // Check the bounds when an nda::ellipsis is encountered (no need to check anything).
55 void check_current_dim(ellipsis) { N += ellipsis_loss + 1; }
56
57 // Accumulate an error message for the current dimension and index.
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";
60 N++;
61 }
62
63 // Accumulate an error message for the current dimension and nda::range.
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";
66 ++N;
67 }
68
69 // Accumulate an error message for the current dimension and nda::range::all_t.
70 void accumulate_error_msg(std::stringstream &, range::all_t) { ++N; }
71
72 // Accumulate an error message for the current dimension and nda::ellipsis.
73 void accumulate_error_msg(std::stringstream &, ellipsis) { N += ellipsis_loss + 1; }
74 };
75
76} // namespace nda::detail
77
78namespace nda {
79
92 template <typename... Args>
93 void assert_in_bounds(int rank, long const *lengths, Args const &...args) {
94 // initialize the bounds checker
95 detail::bound_check_worker w{lengths};
96
97 // number of dimensions that are covered by an nda::ellipsis
98 w.ellipsis_loss = rank - sizeof...(Args);
99
100 // check the bounds on each argument/index
101 (w.check_current_dim(args), ...);
102
103 // if no error, stop here
104 if (!w.error_code) return;
105
106 // accumulate error message and throw
107 w.N = 0;
108 std::stringstream fs;
109 (w.accumulate_error_msg(fs, args), ...);
110 throw std::runtime_error("Index/Range out of bounds:\n" + fs.str());
111 }
112
113} // namespace nda
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.