|
3 | 3 | #include <AMReX_Config.H> |
4 | 4 |
|
5 | 5 | #include <AMReX_BLassert.H> |
6 | | -#include <AMReX_Box.H> |
7 | 6 | #include <AMReX_REAL.H> |
8 | 7 | #include <AMReX_SPACE.H> |
9 | 8 | #include <AMReX_IntVect.H> |
|
12 | 11 |
|
13 | 12 | namespace amrex |
14 | 13 | { |
15 | | - /** |
16 | | - \brief iterates through the IntVects of a Box |
17 | | -
|
18 | | -
|
19 | | - BoxIterator iterates through the IntVects of a box. The actual |
20 | | - sequence of IntVects is implementation-specific. |
21 | | - Typical usage: |
22 | | -
|
23 | | - Box b; |
24 | | - ... |
25 | | - BoxIterator bit (b); |
26 | | - for (bit.begin(); bit.ok(); ++bit) |
27 | | - { |
28 | | - IntVect iv = bit(); |
29 | | - (do operations involving iv) |
30 | | - } |
31 | | - */ |
32 | | - class BoxIterator |
33 | | - { |
34 | | - public: |
35 | | - /// |
| 14 | + |
| 15 | +template<int dim> |
| 16 | +class BoxND; |
| 17 | + |
| 18 | +/** |
| 19 | +* \brief iterates through the IntVects of a Box |
| 20 | +* |
| 21 | +* BoxIteratorND iterates through the IntVects of a box |
| 22 | +* in the same order as a series of nested for loops |
| 23 | +* with the innermost loop iterating over the first dimension. |
| 24 | +* |
| 25 | +* Typical usage using a range-based for loop: |
| 26 | +* \code{.cpp} |
| 27 | +* Box b; |
| 28 | +* ... |
| 29 | +* for (IntVect iv : b.iterator()) { |
| 30 | +* // do operations involving iv |
| 31 | +* } |
| 32 | +* \endcode |
| 33 | +* |
| 34 | +* Using a traditional for loop: |
| 35 | +* \code{.cpp} |
| 36 | +* Box b; |
| 37 | +* ... |
| 38 | +* BoxIterator bit (b); |
| 39 | +* for (bit.begin(); bit.ok(); ++bit) |
| 40 | +* { |
| 41 | +* IntVect iv = bit(); |
| 42 | +* // do operations involving iv |
| 43 | +* } |
| 44 | +* \endcode |
| 45 | +* |
| 46 | +* Note that while regular iteration of the range-based version is reasonably performant, |
| 47 | +* neither version is compatible with omp parallel for or simd autovectorization. |
| 48 | +*/ |
| 49 | +template<int dim> |
| 50 | +class BoxIteratorND |
| 51 | +{ |
| 52 | +public: |
| 53 | + |
36 | 54 | /** |
37 | | - Default constructor. This constructs an invalid iterator. |
38 | | - The user must call define before using. |
| 55 | + * Default constructor. This constructs an invalid iterator. |
| 56 | + * The user must call define before using. |
39 | 57 | */ |
40 | | - BoxIterator () noexcept = default; |
| 58 | + BoxIteratorND () noexcept = default; |
41 | 59 |
|
42 | | - /// |
43 | 60 | /** |
44 | | - Constructs a BoxIterator and associates it with a Box. |
45 | | - Arguments: |
46 | | - a_bx (not modified) the Box to iterate over. |
| 61 | + * Constructs a BoxIteratorND and associates it with a Box. |
| 62 | + * Arguments: |
| 63 | + * a_bx (not modified) the Box to iterate over. |
47 | 64 | */ |
48 | | - explicit BoxIterator (const Box& a_bx) noexcept; |
| 65 | + explicit BoxIteratorND (const BoxND<dim>& a_bx) noexcept { |
| 66 | + define(a_bx); |
| 67 | + } |
49 | 68 |
|
50 | | - void setBox (const Box& a_bx) noexcept; |
| 69 | + void setBox (const BoxND<dim>& a_bx) noexcept { |
| 70 | + define(a_bx); |
| 71 | + } |
| 72 | + |
| 73 | + /** |
| 74 | + * Associates a Box with this BoxIteratorND. |
| 75 | + * Arguments: |
| 76 | + * a_bx (not modified) the Box to iterate over. |
| 77 | + */ |
| 78 | + void define (const BoxND<dim>& a_bx) noexcept { |
| 79 | + if (a_bx.ok() && a_bx.smallEnd().allLE(a_bx.bigEnd())) { |
| 80 | + m_current = a_bx.smallEnd(); |
| 81 | + m_boxLo = a_bx.smallEnd(); |
| 82 | + m_boxHi = a_bx.bigEnd(); |
| 83 | + } else { |
| 84 | + m_current = IntVectND<dim>::TheUnitVector(); |
| 85 | + m_boxLo = IntVectND<dim>::TheUnitVector(); |
| 86 | + m_boxHi = IntVectND<dim>::TheZeroVector(); |
| 87 | + } |
| 88 | + } |
51 | 89 |
|
52 | | - /// |
53 | 90 | /** |
54 | | - Associates a Box with this BoxIterator. |
55 | | - Arguments: |
56 | | - a_bx (not modified) the Box to iterate over. |
| 91 | + * Sets this BoxIteratorND to the first IntVect in its Box. |
| 92 | + * This is the smallEnd vector of the Box. |
57 | 93 | */ |
58 | | - void define (const Box& a_bx) noexcept; |
| 94 | + BoxIteratorND begin () noexcept { |
| 95 | + m_current = m_boxLo; |
| 96 | + return *this; |
| 97 | + } |
59 | 98 |
|
60 | | - /// |
61 | 99 | /** |
62 | | - Sets this BoxIterator to the first IntVect in its Box. The |
63 | | - definition of the "first" IntVect is |
64 | | - implementation-dependent. |
| 100 | + * Get a BoxIteratorND with its vector set to the end of the Box. |
| 101 | + * Should only be used internally by a range-based for loop. |
65 | 102 | */ |
66 | | - void begin () noexcept; |
| 103 | + [[nodiscard]] BoxIteratorND end () const noexcept { |
| 104 | + BoxIteratorND ret = *this; |
| 105 | + // set current of end to the past-the-end IntVect |
| 106 | + ret.m_current = m_boxLo; |
| 107 | + if (m_boxLo.allLE(m_boxHi)) { |
| 108 | + ret.m_current[dim-1] = m_boxHi[dim-1] + 1; |
| 109 | + } |
| 110 | + return ret; |
| 111 | + } |
67 | 112 |
|
68 | | - /// |
69 | 113 | /** |
70 | | - Sets this BoxIterator to the first IntVect in its Box. The |
71 | | - definition of the "first" IntVect is |
72 | | - implementation-dependent. |
| 114 | + * Sets this BoxIteratorND to the first IntVect in its Box. |
| 115 | + * This is the smallEnd vector of the Box. |
73 | 116 | */ |
74 | | - void reset () noexcept; |
| 117 | + void reset () noexcept { |
| 118 | + begin(); |
| 119 | + } |
75 | 120 |
|
76 | | - /// |
77 | 121 | /** |
78 | | - Modifies this BoxIterator to set it to the next location in its |
79 | | - Box. The definition of the "next location" of a Box is |
80 | | - implementation-dependent. |
| 122 | + * Modifies this BoxIteratorND to set it to the next location in its Box. |
81 | 123 | */ |
82 | | - void operator ++ () noexcept; |
| 124 | + BoxIteratorND& operator++ () noexcept { |
| 125 | + next(); |
| 126 | + return *this; |
| 127 | + } |
83 | 128 |
|
84 | | - void next () noexcept; |
| 129 | + /** |
| 130 | + * Modifies this BoxIteratorND to set it to the next location in its Box. |
| 131 | + */ |
| 132 | + void next () noexcept { |
| 133 | + for (int i=0; i<dim; ++i) { |
| 134 | + ++m_current[i]; |
| 135 | + if ((i+1<dim) && m_current[i] > m_boxHi[i]) { |
| 136 | + m_current[i] = m_boxLo[i]; |
| 137 | + continue; |
| 138 | + } |
| 139 | + break; |
| 140 | + } |
| 141 | + } |
85 | 142 |
|
86 | | - /// |
87 | 143 | /** |
88 | | - Returns the value of the InVect for the current location of this |
89 | | - BoxIterator. |
| 144 | + * Returns the value of the InVect for the current location of this BoxIteratorND. |
90 | 145 | */ |
91 | | - [[nodiscard]] const IntVect& operator () () const noexcept; |
| 146 | + [[nodiscard]] const IntVectND<dim>& operator () () const noexcept { |
| 147 | + AMREX_ASSERT(m_current.allLE(m_boxHi)); |
| 148 | + AMREX_ASSERT(m_current.allGE(m_boxLo)); |
| 149 | + return m_current; |
| 150 | + } |
92 | 151 |
|
93 | | - /// |
94 | 152 | /** |
95 | | - Returns true if this BoxIterator's location is within its Box. |
| 153 | + * Returns the value of the InVect for the current location of this BoxIteratorND. |
96 | 154 | */ |
97 | | - [[nodiscard]] bool ok () noexcept; |
98 | | - |
99 | | - protected: |
100 | | - IntVect m_current = IntVect::TheUnitVector(); |
101 | | - IntVect m_boxLo = IntVect::TheUnitVector(); |
102 | | - IntVect m_boxHi = IntVect::TheZeroVector(); |
103 | | - }; |
104 | | - |
105 | | - inline |
106 | | - BoxIterator::BoxIterator (const Box& a_bx) noexcept |
107 | | - { |
108 | | - define(a_bx); |
109 | | - } |
110 | | - |
111 | | - inline |
112 | | - void BoxIterator::begin () noexcept |
113 | | - { |
114 | | - if (m_boxLo <= m_boxHi) { m_current = m_boxLo; } |
115 | | - } |
116 | | - |
117 | | - inline |
118 | | - void BoxIterator::reset () noexcept |
119 | | - { |
120 | | - begin(); |
121 | | - } |
122 | | - |
123 | | - inline |
124 | | - void BoxIterator::operator ++ () noexcept |
125 | | - { |
126 | | - next(); |
127 | | - } |
128 | | - |
129 | | - inline |
130 | | - void BoxIterator::next () noexcept |
131 | | - { |
132 | | - m_current[0]++; |
133 | | -#if AMREX_SPACEDIM >= 2 |
134 | | - if (m_current[0] > m_boxHi[0]) |
135 | | - { |
136 | | - m_current[0] = m_boxLo[0]; |
137 | | - m_current[1]++; |
138 | | -#if AMREX_SPACEDIM >= 3 |
139 | | - if (m_current[1] > m_boxHi[1]) |
140 | | - { |
141 | | - m_current[1] = m_boxLo[1]; |
142 | | - m_current[2]++; |
143 | | - } |
144 | | -#endif |
145 | | - } |
146 | | -#endif |
147 | | - } |
148 | | - |
149 | | - inline |
150 | | - const IntVect& BoxIterator::operator () () const noexcept |
151 | | - { |
152 | | - BL_ASSERT(m_current <= m_boxHi); |
153 | | - BL_ASSERT(m_current >= m_boxLo); |
154 | | - return m_current; |
155 | | - } |
156 | | - |
157 | | - inline |
158 | | - bool BoxIterator::ok () noexcept |
159 | | - { |
160 | | - return (m_current <= m_boxHi); |
161 | | - } |
| 155 | + [[nodiscard]] IntVectND<dim> operator* () const noexcept { |
| 156 | + AMREX_ASSERT(m_current.allLE(m_boxHi)); |
| 157 | + AMREX_ASSERT(m_current.allGE(m_boxLo)); |
| 158 | + // Returning by value gives cleaner assembly output. |
| 159 | + return m_current; |
| 160 | + } |
| 161 | + |
| 162 | + /** |
| 163 | + * Returns true if this BoxIteratorND's location is within its Box. |
| 164 | + */ |
| 165 | + [[nodiscard]] bool ok () const noexcept { |
| 166 | + return m_current.allLE(m_boxHi); |
| 167 | + } |
| 168 | + |
| 169 | + /** |
| 170 | + * Special operator for range-based for loops. |
| 171 | + * Only checks inequality of the last dimension of the current position for better performance. |
| 172 | + * Should only be used internally by a range-based for loop. |
| 173 | + */ |
| 174 | + [[nodiscard]] friend |
| 175 | + bool operator != (const BoxIteratorND& b1, const BoxIteratorND& b2) noexcept { |
| 176 | + // Only check one value for better performance. |
| 177 | + return b1.m_current[dim-1] != b2.m_current[dim-1]; |
| 178 | + } |
| 179 | + |
| 180 | +private: |
| 181 | + IntVectND<dim> m_current = IntVectND<dim>::TheUnitVector(); |
| 182 | + IntVectND<dim> m_boxLo = IntVectND<dim>::TheUnitVector(); |
| 183 | + IntVectND<dim> m_boxHi = IntVectND<dim>::TheZeroVector(); |
| 184 | +}; |
| 185 | + |
| 186 | +using BoxIterator = BoxIteratorND<AMREX_SPACEDIM>; |
| 187 | + |
162 | 188 | } |
163 | 189 | #endif |
0 commit comments