Skip to content

Commit 46255b4

Browse files
committed
Add range-based for and ND to BoxIterator
1 parent a67a8c6 commit 46255b4

File tree

7 files changed

+186
-194
lines changed

7 files changed

+186
-194
lines changed

Src/Base/AMReX_Box.H

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <AMReX_Algorithm.H>
77
#include <AMReX_ArrayLim.H>
8+
#include <AMReX_BoxIterator.H>
89
#include <AMReX_ccse-mpi.H>
910
#include <AMReX_IntVect.H>
1011
#include <AMReX_IndexType.H>
@@ -25,6 +26,8 @@ template<int dim>
2526
class BoxND;
2627
using Box = BoxND<AMREX_SPACEDIM>;
2728
class BoxCommHelper;
29+
template<int dim>
30+
class BoxIteratorND;
2831

2932
/**
3033
* \brief A Rectangular Domain on an Integer Lattice
@@ -783,6 +786,21 @@ public:
783786
return *this;
784787
}
785788

789+
/**
790+
* \brief Returns a BoxIteratorND that can be used to loop over the IntVects
791+
* contained by the BoxND.
792+
* \code{.cpp}
793+
* Box b;
794+
* ...
795+
* for (IntVect iv : b.iterator()) {
796+
* // do operations involving iv
797+
* }
798+
* \endcode
799+
*/
800+
[[nodiscard]] BoxIteratorND<dim> iterator () const noexcept {
801+
return BoxIteratorND<dim>{*this};
802+
}
803+
786804
[[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
787805
static constexpr std::size_t ndims () noexcept {
788806
return static_cast<std::size_t>(dim);

Src/Base/AMReX_BoxIterator.H

Lines changed: 149 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include <AMReX_Config.H>
44

55
#include <AMReX_BLassert.H>
6-
#include <AMReX_Box.H>
76
#include <AMReX_REAL.H>
87
#include <AMReX_SPACE.H>
98
#include <AMReX_IntVect.H>
@@ -12,152 +11,179 @@
1211

1312
namespace amrex
1413
{
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+
3654
/**
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.
3957
*/
40-
BoxIterator () noexcept = default;
58+
BoxIteratorND () noexcept = default;
4159

42-
///
4360
/**
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.
4764
*/
48-
explicit BoxIterator (const Box& a_bx) noexcept;
65+
explicit BoxIteratorND (const BoxND<dim>& a_bx) noexcept {
66+
define(a_bx);
67+
}
4968

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+
}
5189

52-
///
5390
/**
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.
5793
*/
58-
void define (const Box& a_bx) noexcept;
94+
BoxIteratorND begin () noexcept {
95+
m_current = m_boxLo;
96+
return *this;
97+
}
5998

60-
///
6199
/**
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.
65102
*/
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+
}
67112

68-
///
69113
/**
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.
73116
*/
74-
void reset () noexcept;
117+
void reset () noexcept {
118+
begin();
119+
}
75120

76-
///
77121
/**
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.
81123
*/
82-
void operator ++ () noexcept;
124+
BoxIteratorND& operator++ () noexcept {
125+
next();
126+
return *this;
127+
}
83128

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+
}
85142

86-
///
87143
/**
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.
90145
*/
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+
}
92151

93-
///
94152
/**
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.
96154
*/
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+
162188
}
163189
#endif

Src/Base/AMReX_BoxIterator.cpp

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)