diff --git a/Src/Base/AMReX_BaseFwd.H b/Src/Base/AMReX_BaseFwd.H index 947535cfa57..824a6c504e7 100644 --- a/Src/Base/AMReX_BaseFwd.H +++ b/Src/Base/AMReX_BaseFwd.H @@ -22,7 +22,9 @@ class DistributionMapping; class Geometry; class Box; -class IntVect; +template +class IntVectND; +using IntVect = IntVectND; class IndexType; struct Dim3; struct XDim3; diff --git a/Src/Base/AMReX_IntVect.H b/Src/Base/AMReX_IntVect.H index e2c0adf120f..2cf48053cd2 100644 --- a/Src/Base/AMReX_IntVect.H +++ b/Src/Base/AMReX_IntVect.H @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -12,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -34,34 +35,47 @@ int coarsen (int i, int ratio) noexcept } /** -* An Integer Vector in SPACEDIM-Dimensional Space +* An Integer Vector in dim-Dimensional Space * -* The class IntVect is an implementation of an integer vector in a -* SPACEDIM-dimensional space. It represents a point in a discrete space. -* IntVect values are accessed using the operator[] function, as for a normal +* The class IntVectND is an implementation of an integer vector in a +* dim-dimensional space. It represents a point in a discrete space. +* IntVectND values are accessed using the operator[] function, as for a normal * C++ array. In addition, the basic arithmetic operators have been overloaded * to implement scaling and translation operations. */ -class IntVect +template +class IntVectND { - friend MPI_Datatype ParallelDescriptor::Mpi_typemap::type(); public: + static_assert(dim >= 1, "The number of dimensions of IntVectND must be positive"); - class shift_hasher { - private: - static constexpr unsigned shift1 = sizeof(size_t)>=8 ? 20 : 10; - static constexpr unsigned shift2 = sizeof(size_t)>=8 ? 40 : 20; - public: - std::size_t operator()(const IntVect& vec) const noexcept + struct shift_hasher { + std::size_t operator()(const IntVectND& vec) const noexcept { - AMREX_D_DECL(std::size_t ret0 = vec[0], ret1 = vec[1], ret2 = vec[2]); -#if AMREX_SPACEDIM == 1 - return ret0; -#elif AMREX_SPACEDIM == 2 - return ret0 ^ (ret1 << shift1); -#else - return ret0 ^ (ret1 << shift1) ^ (ret2 << shift2); -#endif + static constexpr unsigned shift1 = sizeof(size_t)>=8 ? 20 : 10; + static constexpr unsigned shift2 = sizeof(size_t)>=8 ? 40 : 20; + if constexpr (dim == 1) { + return static_cast(vec[0]); + } else if constexpr (dim == 2) { + return static_cast(vec[0]) ^ + (static_cast(vec[1]) << shift1); + } else if constexpr (dim == 3) { + return static_cast(vec[0]) ^ + (static_cast(vec[1]) << shift1) ^ + (static_cast(vec[2]) << shift2); + } else { + std::size_t seed = dim; + // hash function from + // https://stackoverflow.com/questions/20511347/a-good-hash-function-for-a-vector + for (int i=0; i(vec[i]); + x = ((x >> 16) ^ x) * 0x45d9f3b; + x = ((x >> 16) ^ x) * 0x45d9f3b; + x = (x >> 16) ^ x; + seed ^= x + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; + } } }; @@ -69,92 +83,114 @@ public: /// /** - This is an IntVect all of whose components are equal to zero. + * \brief Construct an IntVectND whose components are all zero. */ - static const IntVect Zero; + constexpr IntVectND () noexcept {} // cannot use = default due to Clang bug // NOLINT - /// /** - This is an IntVect all of whose components are equal to one. + * \brief Construct an IntVectND given the specific values for its + * coordinates. The inputs for this constructor are N integers, + * where N is equal to the number of dimensions of the IntVectND. */ - static const IntVect Unit; - - /// - /** - * \brief Construct an IntVect whose components are all zero. - */ - constexpr IntVect () noexcept {} // cannot use = default due to Clang bug // NOLINT + template , + int> = 0> + AMREX_GPU_HOST_DEVICE + constexpr IntVectND (int i, int j, Args...ks) noexcept : vect{i, j, static_cast(ks)...} {} /** - * \brief Construct an IntVect given the specific values for its - * coordinates. AMREX_D_DECL is a macro that sets the constructor - * to take AMREX_SPACEDIM arguments. + * \brief Construct an IntVectND whose components are all the same. */ -#if (AMREX_SPACEDIM > 1) - AMREX_GPU_HOST_DEVICE - constexpr IntVect (AMREX_D_DECL(int i, int j, int k)) noexcept : vect{AMREX_D_DECL(i,j,k)} {} -#endif - AMREX_GPU_HOST_DEVICE - explicit constexpr IntVect (int i) noexcept : vect{AMREX_D_DECL(i,i,i)} {} + explicit constexpr IntVectND (int s) noexcept { + for (int i=0; i. It is an error if + * \brief Construct an IntVectND from an Vector. It is an error if * the Vector doesn't have the same dimension as this - * IntVect. + * IntVectND. */ - explicit IntVect (const Vector& a) noexcept : vect{AMREX_D_DECL(a[0],a[1],a[2])} { - BL_ASSERT(a.size() == AMREX_SPACEDIM); + explicit IntVectND (const Vector& a) noexcept { + BL_ASSERT(a.size() == dim); + for (int i=0; i. + * \brief Construct an IntVectND from an Array. */ - explicit IntVect (const Array& a) noexcept - : vect{AMREX_D_DECL(a[0],a[1],a[2])} {} + explicit IntVectND (const Array& a) noexcept { + for (int i=0; i = 0> + explicit constexpr IntVectND (Dim3 const& a) noexcept { + vect[0] = a.x; + if constexpr (dim >= 2) { + vect[1] = a.y; + } + if constexpr (dim == 3) { + vect[2] = a.z; + } + } // dtor, copy-ctor, copy-op=, move-ctor, and move-op= are compiler generated. + template = 0> [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE Dim3 dim3 () const noexcept { -#if (AMREX_SPACEDIM == 1) - return Dim3{vect[0],0,0}; -#elif (AMREX_SPACEDIM == 2) - return Dim3{vect[0],vect[1],0}; -#else - return Dim3{vect[0],vect[1],vect[2]}; -#endif + if constexpr (dim == 1) { + return Dim3{vect[0],0,0}; + } else if constexpr (dim == 2) { + return Dim3{vect[0],vect[1],0}; + } else { + return Dim3{vect[0],vect[1],vect[2]}; + } } #if __cplusplus >= 201402L template< typename T = int > AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - Array + Array toArray () const noexcept { - return Array{ - AMREX_D_DECL(T(vect[0]), T(vect[1]), T(vect[2])) - }; + Array ret {}; + for (int i=0; i vect[1] ? vect[0] : vect[1]); -#else - int r = vect[0] > vect[1] ? vect[0] : vect[1]; - return (r > vect[2]) ? r : vect[2]; -#endif + int retval = vect[0]; + for (int i=1; i vect[i] ? retval : vect[i]; + } + return retval; } //! minimum (no absolute values) value [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int min () const noexcept { -#if (AMREX_SPACEDIM == 1) - return vect[0]; -#elif (AMREX_SPACEDIM == 2) - return (vect[0] < vect[1] ? vect[0] : vect[1]); -#else - int r = vect[0] < vect[1] ? vect[0] : vect[1]; - return (r < vect[2]) ? r : vect[2]; -#endif + int retval = vect[0]; + for (int i=1; i=0 && i < AMREX_SPACEDIM); return vect[i]; } + //! Returns a reference to the i'th coordinate of the IntVectND. + [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE constexpr + int& operator[] (int i) noexcept { BL_ASSERT(i>=0 && i < dim); return vect[i]; } - //! Returns the i'th coordinate of the IntVect. - [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - const int& operator[] (int i) const noexcept { BL_ASSERT(i>=0 && i < AMREX_SPACEDIM); return vect[i]; } + //! Returns the i'th coordinate of the IntVectND. + [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE constexpr + const int& operator[] (int i) const noexcept { BL_ASSERT(i>=0 && i < dim); return vect[i]; } - //! Returns a pointer to the first element of the IntVect. - [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + //! Returns a reference to the i'th coordinate of the IntVectND. Used by structured bindings. + template + [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE constexpr + int& get () noexcept {static_assert(0<=i && i + [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE constexpr + const int& get () const noexcept {static_assert(0<=i && i=0 && i < AMREX_SPACEDIM); vect[i] = val; return *this; + BL_ASSERT(i>=0 && i& rhs) const noexcept { - return AMREX_D_TERM(vect[0] == rhs[0], && vect[1] == rhs[1], && vect[2] == rhs[2]); + bool retval = vect[0] == rhs[0]; + for (int i=1; i& rhs) const noexcept { - return AMREX_D_TERM(vect[0] != rhs[0], || vect[1] != rhs[1], || vect[2] != rhs[2]); + bool retval = vect[0] != rhs[0]; + for (int i=1; i& rhs) const noexcept { -#if (AMREX_SPACEDIM == 1) - return vect[0] < rhs[0]; -#elif (AMREX_SPACEDIM == 2) - return (vect[1] < rhs[1]) || ((vect[1] == rhs[1]) && (vect[0] < rhs[0])); -#else - return (vect[2] < rhs[2]) || ((vect[2] == rhs[2]) && - ( (vect[1] < rhs[1]) || ((vect[1] == rhs[1]) && (vect[0] < rhs[0])) )); -#endif + for (int i=dim-1; i>=0; --i) { + if (vect[i] < rhs[i]) { + return true; + } else if (vect[i] > rhs[i]) { + return false; + } + } + return false; } //! Return true if this is lexicographically less than or equal to rhs. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - bool operator<= (const IntVect& rhs) const noexcept + bool operator<= (const IntVectND& rhs) const noexcept { return !(rhs < *this); } //! Return true if this is lexicographically greater than rhs. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - bool operator> (const IntVect& rhs) const noexcept + bool operator> (const IntVectND& rhs) const noexcept { return rhs < *this; } //! Return true if this is lexicographically greater than or equal to rhs. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - bool operator>= (const IntVect& rhs) const noexcept + bool operator>= (const IntVectND& rhs) const noexcept { return !(*this < rhs); } @@ -294,9 +350,13 @@ public: * NOTE: This is NOT a strict weak ordering usable by STL sorting algorithms. */ [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - bool allLT (const IntVect& rhs) const noexcept + bool allLT (const IntVectND& rhs) const noexcept { - return AMREX_D_TERM(vect[0] < rhs[0], && vect[1] < rhs[1], && vect[2] < rhs[2]); + bool retval = vect[0] < rhs[0]; + for (int i=1; i& rhs) const noexcept { - return AMREX_D_TERM(vect[0] <= rhs[0], && vect[1] <= rhs[1], && vect[2] <= rhs[2]); + bool retval = vect[0] <= rhs[0]; + for (int i=1; i& rhs) const noexcept { - return AMREX_D_TERM(vect[0] > rhs[0], && vect[1] > rhs[1], && vect[2] > rhs[2]); + bool retval = vect[0] > rhs[0]; + for (int i=1; i rhs[i]; + } + return retval; } /** * \brief Returns true if this is greater than argument for all components. @@ -338,16 +414,24 @@ public: [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool allGT (int rhs) const noexcept { - return AMREX_D_TERM(vect[0] > rhs, && vect[1] > rhs, && vect[2] > rhs); + bool retval = vect[0] > rhs; + for (int i=1; i rhs; + } + return retval; } /** * \brief Returns true if this is greater than or equal to argument for all components. * NOTE: This is NOT a strict weak ordering usable by STL sorting algorithms. */ [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - bool allGE (const IntVect& rhs) const noexcept + bool allGE (const IntVectND& rhs) const noexcept { - return AMREX_D_TERM(vect[0] >= rhs[0], && vect[1] >= rhs[1], && vect[2] >= rhs[2]); + bool retval = vect[0] >= rhs[0]; + for (int i=1; i= rhs[i]; + } + return retval; } /** * \brief Returns true if this is greater than or equal to argument for all components. @@ -355,280 +439,413 @@ public: [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool allGE (int rhs) const noexcept { - return AMREX_D_TERM(vect[0] >= rhs, && vect[1] >= rhs, && vect[2] >= rhs); + bool retval = vect[0] >= rhs; + for (int i=1; i= rhs; + } + return retval; } //! Unary plus -- for completeness. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect operator+ () const noexcept { return *this; } + IntVectND operator+ () const noexcept { return *this; } //! Unary Minus -- negates all components. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect operator- () const noexcept { return IntVect(AMREX_D_DECL(-vect[0], -vect[1], -vect[2] )); } - //! Modifies IntVect by addition of a scalar to each component. + IntVectND operator- () const noexcept { + IntVectND retval(0); + for (int i=0; i& operator+= (int s) noexcept { - AMREX_D_EXPR(vect[0] += s, vect[1] += s, vect[2] += s); return *this; + for (int i=0; i& operator+= (const IntVectND& p) noexcept { - AMREX_D_EXPR(vect[0] += p[0], vect[1] += p[1], vect[2] += p[2]); return *this; + for (int i=0; i& operator*= (int s) noexcept { - AMREX_D_EXPR(vect[0] *= s, vect[1] *= s, vect[2] *= s); return *this; + for (int i=0; i& operator*= (const IntVectND& p) noexcept { - AMREX_D_EXPR(vect[0] *= p[0], vect[1] *= p[1], vect[2] *= p[2]); return *this; + for (int i=0; i& operator/= (int s) noexcept { - AMREX_D_EXPR(vect[0] /= s, vect[1] /= s, vect[2] /= s); return *this; + for (int i=0; i& operator/= (const IntVectND& p) noexcept { - AMREX_D_EXPR(vect[0] /= p[0], vect[1] /= p[1], vect[2] /= p[2]); return *this; + for (int i=0; i& operator-= (int s) noexcept { - AMREX_D_EXPR(vect[0] -= s, vect[1] -= s, vect[2] -= s); return *this; + for (int i=0; i& operator-= (const IntVectND& p) noexcept { - AMREX_D_EXPR(vect[0] -= p[0], vect[1] -= p[1], vect[2] -= p[2]); return *this; + for (int i=0; i operator+ (const IntVectND& p) const noexcept { - return IntVect(AMREX_D_DECL(vect[0] + p[0], vect[1] + p[1], vect[2] + p[2])); + IntVectND retval = *this; + return retval += p; } - //! Return an IntVect that is this IntVect + s. + //! Return an IntVectND that is this IntVectND + s. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect operator+ (int s) const noexcept + IntVectND operator+ (int s) const noexcept { - return IntVect(AMREX_D_DECL(vect[0] + s, vect[1] + s, vect[2] + s)); + IntVectND retval = *this; + return retval += s; } - //! Returns component-wise difference of IntVect and argument. + //! Returns component-wise difference of IntVectND and argument. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect operator- (const IntVect& p) const noexcept + IntVectND operator- (const IntVectND& p) const noexcept { - return IntVect(AMREX_D_DECL(vect[0] - p[0], vect[1] - p[1], vect[2] - p[2])); + IntVectND retval = *this; + return retval -= p; } - //! Return an IntVect that is this IntVect - s. + //! Return an IntVectND that is this IntVectND - s. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect operator- (int s) const noexcept + IntVectND operator- (int s) const noexcept { - return IntVect(AMREX_D_DECL(vect[0] - s, vect[1] - s, vect[2] - s)); + IntVectND retval = *this; + return retval -= s; } - //! Returns component-wise product of IntVect and argument. + //! Returns component-wise product of IntVectND and argument. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect operator* (const IntVect& p) const noexcept + IntVectND operator* (const IntVectND& p) const noexcept { - return IntVect(AMREX_D_DECL(vect[0] * p[0], vect[1] * p[1], vect[2] * p[2])); + IntVectND retval = *this; + return retval *= p; } - //! Returns component-wise product of IntVect and s. + //! Returns component-wise product of IntVectND and s. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect operator* (int s) const noexcept + IntVectND operator* (int s) const noexcept { - return IntVect(AMREX_D_DECL(vect[0] * s, vect[1] * s, vect[2] * s)); + IntVectND retval = *this; + return retval *= s; } - //! Returns component-wise division of IntVect by argument. + //! Returns component-wise division of IntVectND by argument. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect operator/ (const IntVect& p) const noexcept + IntVectND operator/ (const IntVectND& p) const noexcept { - return IntVect(AMREX_D_DECL(vect[0] / p[0], vect[1] / p[1], vect[2] / p[2])); + IntVectND retval = *this; + return retval /= p; } - //! Returns component-wise division of IntVect by s. + //! Returns component-wise division of IntVectND by s. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect operator/ (int s) const noexcept + IntVectND operator/ (int s) const noexcept { - return IntVect(AMREX_D_DECL(vect[0] / s, vect[1] / s, vect[2] / s)); + IntVectND retval = *this; + return retval /= s; } - //! Modifies IntVect by taking component-wise min with argument. + //! Modifies IntVectND by taking component-wise min with argument. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect& min (const IntVect& p) noexcept + IntVectND& min (const IntVectND& p) noexcept { - AMREX_D_EXPR(vect[0] = (vect[0] < p.vect[0] ? vect[0] : p.vect[0]), - vect[1] = (vect[1] < p.vect[1] ? vect[1] : p.vect[1]), - vect[2] = (vect[2] < p.vect[2] ? vect[2] : p.vect[2])); + for (int i=0; i& max (const IntVectND& p) noexcept { - AMREX_D_EXPR(vect[0] = (vect[0] > p.vect[0] ? vect[0] : p.vect[0]), - vect[1] = (vect[1] > p.vect[1] ? vect[1] : p.vect[1]), - vect[2] = (vect[2] > p.vect[2] ? vect[2] : p.vect[2])); + for (int i=0; i p.vect[i] ? vect[i] : p.vect[i]); + } return *this; } - //! Modify IntVect by multiplying each coordinate by s. + //! Modify IntVectND by multiplying each coordinate by s. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect& scale (int s) noexcept { AMREX_D_EXPR(vect[0] *= s, vect[1] *= s, vect[2] *= s); return *this; } + IntVectND& scale (int s) noexcept { + for (int i=0; i& reflect (int ref_ix, int idir) noexcept { - BL_ASSERT(idir >= 0 && idir < AMREX_SPACEDIM); + BL_ASSERT(idir >= 0 && idir < dim); vect[idir] = -vect[idir] + 2*ref_ix; return *this; } - //! Modify IntVect by adding s to given coordinate. + //! Modify IntVectND by adding s to given coordinate. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect& shift (int coord, int s) noexcept + IntVectND& shift (int coord, int s) noexcept { - BL_ASSERT(coord >= 0 && coord < AMREX_SPACEDIM); vect[coord] += s; return *this; + BL_ASSERT(coord >= 0 && coord < dim); vect[coord] += s; return *this; } //! Equivalent to shift(0,iv[0]).shift(1,iv[1]) ... AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect& shift (const IntVect& iv) noexcept { *this += iv; return *this; } - //! Modify IntVect by adding s to each coordinate. + IntVectND& shift (const IntVectND& iv) noexcept { *this += iv; return *this; } + //! Modify IntVectND by adding s to each coordinate. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect& diagShift (int s) noexcept + IntVectND& diagShift (int s) noexcept { - AMREX_D_EXPR(vect[0] += s, vect[1] += s, vect[2] += s); return *this; + for (int i=0; i by component-wise integer projection. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect& coarsen (const IntVect& p) noexcept; - //! Modify IntVect by component-wise integer projection. + IntVectND& coarsen (const IntVectND& p) noexcept; + //! Modify IntVectND by component-wise integer projection. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - IntVect& coarsen (int p) noexcept; + IntVectND& coarsen (int p) noexcept; /** - * \brief This static member function returns a reference to a constant IntVect - * object, all of whose AMREX_SPACEDIM arguments are set to zero (0). - * Figuratively, it is the zero vector in AMREX_SPACEDIM-dimensional space. + * \brief This static member function returns a reference to a constant IntVectND + * object, all of whose dim arguments are set to zero (0). + * Figuratively, it is the zero vector in dim-dimensional space. * It is provided as a convenient way to specify the zero vector. */ AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static constexpr IntVect TheZeroVector () noexcept { - return IntVect(0); + static constexpr IntVectND TheZeroVector () noexcept { + return IntVectND(0); } /** - * \brief This static member function returns a reference to a constant IntVect - * object, all of whose AMREX_SPACEDIM arguments are set to one (1). - * Figuratively, it is the unit vector in AMREX_SPACEDIM-dimensional space. + * \brief This static member function returns a reference to a constant IntVectND + * object, all of whose dim arguments are set to one (1). + * Figuratively, it is the unit vector in dim-dimensional space. * It is provided as a convenient way to specify the unit vector. */ AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static constexpr IntVect TheUnitVector () noexcept { - return IntVect(1); + static constexpr IntVectND TheUnitVector () noexcept { + return IntVectND(1); } /** - * \brief This static member function returns a reference to a constant IntVect - * object, all of whose AMREX_SPACEDIM arguments are set to zero except that + * \brief This static member function returns a reference to a constant IntVectND + * object, all of whose dim arguments are set to zero except that * the d-direction is set to one. */ AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static constexpr IntVect TheDimensionVector (int d) noexcept { - return (d==0) ? IntVect(AMREX_D_DECL(1,0,0)) : - ((d==1) ? IntVect(AMREX_D_DECL(0,1,0)) : - IntVect(AMREX_D_DECL(0,0,1))); + static constexpr IntVectND TheDimensionVector (int d) noexcept { + IntVectND retval(0); + retval[d] = 1; + return retval; } /** - * \brief This static member function returns a reference to a constant IntVect - * object, all of whose AMREX_SPACEDIM arguments are set to IndexType::NODE. + * \brief This static member function returns a reference to a constant IntVectND + * object, all of whose dim arguments are set to IndexType::NODE. * It is provided as a convenience to our users when defining Boxes. */ AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static constexpr IntVect TheNodeVector () noexcept { - return IntVect(1); + static constexpr IntVectND TheNodeVector () noexcept { + return IntVectND(1); } /** - * \brief This static member function returns a reference to a constant IntVect - * object, all of whose AMREX_SPACEDIM arguments are set to IndexType::CELL. + * \brief This static member function returns a reference to a constant IntVectND + * object, all of whose dim arguments are set to IndexType::CELL. * It is provided as a convenience to our users when defining Boxes. */ AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static constexpr IntVect TheCellVector () noexcept { - return IntVect(0); + static constexpr IntVectND TheCellVector () noexcept { + return IntVectND(0); } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static constexpr IntVect TheMaxVector () noexcept { - return IntVect(std::numeric_limits::max()); + static constexpr IntVectND TheMaxVector () noexcept { + return IntVectND(std::numeric_limits::max()); } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static constexpr IntVect TheMinVector () noexcept { - return IntVect(std::numeric_limits::lowest()); + static constexpr IntVectND TheMinVector () noexcept { + return IntVectND(std::numeric_limits::lowest()); } -private: + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static constexpr std::size_t size () noexcept { + return static_cast(dim); + } + + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static constexpr int isize () noexcept { + return dim; + } - friend std::ostream& operator<< (std::ostream& os, const IntVect& iv); - friend std::istream& operator>> (std::istream& is, IntVect& iv); + using value_type = int; - int vect[AMREX_SPACEDIM] = {AMREX_D_DECL(0,0,0)}; + /** + * \brief Returns a new IntVectND of size new_dim and + * assigns the first new_dim values of this IntVectND to it. + */ + template + [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + IntVectND shrink () const noexcept { + static_assert(new_dim <= dim); + return IntVectND(this->begin()); + } + + /** + * \brief Returns a new IntVectND of size new_dim and + * assigns all values of this IntVectND to it andĀ fill_extra to the remaining elements. + */ + template + [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + IntVectND expand (int fill_extra=0) const noexcept { + static_assert(new_dim >= dim); + IntVectND retval(fill_extra); + for (int i=0; i + [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + IntVectND resize (int fill_extra=0) const noexcept { + if constexpr (new_dim > dim) { + return expand(fill_extra); + } else { + return shrink(); + } + } + + /** + This is an IntVect all of whose components are equal to zero. + */ + static const IntVectND Zero; + + /** + This is an IntVect all of whose components are equal to one. + */ + static const IntVectND Unit; + +private: + + int vect[dim] = {}; }; +template +inline constexpr const IntVectND IntVectND::Zero{0}; + +template +inline constexpr const IntVectND IntVectND::Unit{1}; + +// Template deduction guide for IntVectND +template +AMREX_GPU_HOST_DEVICE // __device__ for HIP +IntVectND(const Array&) -> IntVectND; + +// Template deduction guide for IntVectND +template , + int> = 0> +AMREX_GPU_HOST_DEVICE // __device__ for HIP +IntVectND(int, int, Args...) -> IntVectND; + +using IntVect = IntVectND; + +template AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect& -IntVect::coarsen (int s) noexcept +IntVectND& +IntVectND::coarsen (int s) noexcept { BL_ASSERT(s > 0); switch (s) { case 1: break; case 2: - AMREX_D_TERM(vect[0] = (vect[0]<0) ? -std::abs(vect[0]+1)/2-1 : vect[0]/2;, - vect[1] = (vect[1]<0) ? -std::abs(vect[1]+1)/2-1 : vect[1]/2;, - vect[2] = (vect[2]<0) ? -std::abs(vect[2]+1)/2-1 : vect[2]/2;); + for (int i=0; i AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect& -IntVect::coarsen (const IntVect& p) noexcept +IntVectND& +IntVectND::coarsen (const IntVectND& p) noexcept { BL_ASSERT(p.allGT(0)); - AMREX_D_TERM(vect[0] = amrex::coarsen(vect[0], p.vect[0]);, - vect[1] = amrex::coarsen(vect[1], p.vect[1]);, - vect[2] = amrex::coarsen(vect[2], p.vect[2]);); + for (int i=0; i AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int -IntVect::maxDir(bool a_doAbsValue) const noexcept +IntVectND::maxDir(bool a_doAbsValue) const noexcept { int retval = 0; if(a_doAbsValue) { int maxval = std::abs((*this)[0]); - for(int idir = 1; idir < SpaceDim; idir++) + for(int idir = 1; idir < dim; idir++) { int curval = std::abs((*this)[idir]); if(curval > maxval) @@ -641,7 +858,7 @@ IntVect::maxDir(bool a_doAbsValue) const noexcept else { int maxval = (*this)[0]; - for(int idir = 1; idir < SpaceDim; idir++) + for(int idir = 1; idir < dim; idir++) { int curval = (*this)[idir]; if(curval > maxval) @@ -655,187 +872,346 @@ IntVect::maxDir(bool a_doAbsValue) const noexcept } //! Returns p + s. +template AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect operator+ (int s, const IntVect& p) noexcept +IntVectND operator+ (int s, const IntVectND& p) noexcept { - return IntVect(AMREX_D_DECL(p[0] + s, p[1] + s, p[2] + s)); + IntVectND retval = p; + for (int i=0; i AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE AMREX_GPU_HOST_DEVICE -IntVect operator- (int s, const IntVect& p) noexcept +IntVectND operator- (int s, const IntVectND& p) noexcept { - return IntVect(AMREX_D_DECL(s - p[0], s - p[1], s - p[2])); + IntVectND retval = p; + for (int i=0; i AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect operator* (int s, const IntVect& p) noexcept +IntVectND operator* (int s, const IntVectND& p) noexcept { - return IntVect(AMREX_D_DECL(s * p[0], s * p[1], s * p[2])); + IntVectND retval = p; + for (int i=0; i AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect -min (const IntVect& p1, const IntVect& p2) noexcept +IntVectND +min (const IntVectND& p1, const IntVectND& p2) noexcept { - IntVect p(p1); + IntVectND p(p1); p.min(p2); return p; } +template AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect -elemwiseMin (const IntVect& p1, const IntVect& p2) noexcept +IntVectND +elemwiseMin (const IntVectND& p1, const IntVectND& p2) noexcept { - IntVect p(p1); + IntVectND p(p1); p.min(p2); return p; } /** - * \brief Returns the IntVect that is the component-wise maximum of two - * argument IntVects. + * \brief Returns the IntVectND that is the component-wise maximum of two + * argument IntVectNDs. */ +template AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect -max (const IntVect& p1, const IntVect& p2) noexcept +IntVectND +max (const IntVectND& p1, const IntVectND& p2) noexcept { - IntVect p(p1); + IntVectND p(p1); p.max(p2); return p; } +template AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect -elemwiseMax (const IntVect& p1, const IntVect& p2) noexcept +IntVectND +elemwiseMax (const IntVectND& p1, const IntVectND& p2) noexcept { - IntVect p(p1); + IntVectND p(p1); p.max(p2); return p; } /** * \brief Returns a basis vector in the given coordinate direction; - * eg. IntVect BASISV(1) == (0,1,0). Note that the coordinate + * eg. IntVectND<3> BASISV<3>(1) == (0,1,0). Note that the coordinate * directions are zero based. */ +template AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect +IntVectND BASISV (int dir) noexcept { - BL_ASSERT(dir >= 0 && dir < AMREX_SPACEDIM); - IntVect tmp; + BL_ASSERT(dir >= 0 && dir < dim); + IntVectND tmp(0); tmp[dir] = 1; return tmp; } /** - * \brief Returns a IntVect obtained by multiplying each of the - * components of this IntVect by s. + * \brief Returns a IntVectND obtained by multiplying each of the + * components of this IntVectND by s. */ +template AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect -scale (const IntVect& p, int s) noexcept +IntVectND +scale (const IntVectND& p, int s) noexcept { - return IntVect(AMREX_D_DECL(s * p[0], s * p[1], s * p[2])); + return IntVectND(p).scale(s); } /** - * \brief Returns an IntVect that is the reflection of input in the + * \brief Returns an IntVectND that is the reflection of input in the * plane which passes through ref_ix and normal to the * coordinate direction idir. */ +template AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect -reflect (const IntVect& a, int ref_ix, int idir) noexcept +IntVectND +reflect (const IntVectND& a, int ref_ix, int idir) noexcept { - BL_ASSERT(idir >= 0 && idir < AMREX_SPACEDIM); - IntVect b(a); - b[idir] = -b[idir] + 2*ref_ix; - return b; + return IntVectND(a).reflect(ref_ix, idir); } /** - * \brief Returns IntVect obtained by adding s to each of the - * components of this IntVect. + * \brief Returns IntVectND obtained by adding s to each of the + * components of this IntVectND. */ +template AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect -diagShift (const IntVect& p, int s) noexcept +IntVectND +diagShift (const IntVectND& p, int s) noexcept { - return IntVect(AMREX_D_DECL(p[0] + s, p[1] + s, p[2] + s)); + return p + s; } /** - * \brief Returns an IntVect that is the component-wise integer + * \brief Returns an IntVectND that is the component-wise integer * projection of p by s. */ +template AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect -coarsen (const IntVect& p, int s) noexcept +IntVectND +coarsen (const IntVectND& p, int s) noexcept { BL_ASSERT(s > 0); - IntVect v = p; + IntVectND v = p; v.coarsen(s); return v; } /** - * \brief Returns an IntVect which is the component-wise integer - * projection of IntVect p1 by IntVect p2. + * \brief Returns an IntVectND which is the component-wise integer + * projection of IntVectND p1 by IntVectND p2. */ +template AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -IntVect -coarsen (const IntVect& p1, const IntVect& p2) noexcept +IntVectND +coarsen (const IntVectND& p1, const IntVectND& p2) noexcept { - IntVect v = p1; + IntVectND v = p1; v.coarsen(p2); return v; } +template = 0> AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -Dim3 refine (Dim3 const& coarse, IntVect const& ratio) noexcept +Dim3 refine (Dim3 const& coarse, IntVectND const& ratio) noexcept { -#if (AMREX_SPACEDIM == 1) - return {coarse.x*ratio[0], coarse.y, coarse.z}; -#elif (AMREX_SPACEDIM == 2) - return {coarse.x*ratio[0], coarse.y*ratio[1], coarse.z}; -#else - return {coarse.x*ratio[0], coarse.y*ratio[1], coarse.z*ratio[2]}; -#endif + if constexpr (dim == 1) { + return Dim3{coarse.x*ratio[0], coarse.y, coarse.z}; + } else if constexpr (dim == 2) { + return Dim3{coarse.x*ratio[0], coarse.y*ratio[1], coarse.z}; + } else { + return Dim3{coarse.x*ratio[0], coarse.y*ratio[1], coarse.z*ratio[2]}; + } } +template = 0> AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -Dim3 coarsen (Dim3 const& fine, IntVect const& ratio) noexcept +Dim3 coarsen (Dim3 const& fine, IntVectND const& ratio) noexcept { -#if (AMREX_SPACEDIM == 1) - return {amrex::coarsen(fine.x,ratio[0]), fine.y, fine.z}; -#elif (AMREX_SPACEDIM == 2) - return {amrex::coarsen(fine.x,ratio[0]), amrex::coarsen(fine.y, ratio[1]), fine.z}; -#else - return {amrex::coarsen(fine.x, ratio[0]), - amrex::coarsen(fine.y, ratio[1]), - amrex::coarsen(fine.z, ratio[2])}; -#endif + if constexpr (dim == 1) { + return Dim3{amrex::coarsen(fine.x, ratio[0]), + fine.y, + fine.z}; + } else if constexpr (dim == 2) { + return Dim3{amrex::coarsen(fine.x, ratio[0]), + amrex::coarsen(fine.y, ratio[1]), + fine.z}; + } else { + return Dim3{amrex::coarsen(fine.x, ratio[0]), + amrex::coarsen(fine.y, ratio[1]), + amrex::coarsen(fine.z, ratio[2])}; + } } +namespace detail { + std::ostream& int_vector_write (std::ostream& os, const int* iv, int dim); + std::istream& int_vector_read (std::istream& is, int* iv, int dim); + + template + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE constexpr + void IntVectCat_imp (int*& dst, const IntVectND& src) noexcept { + for (int i=0; i + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE constexpr + void IntVectSplit_imp2 (IntVectND& dst, const int*& src) noexcept { + for (int i=0; i + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE constexpr + T IntVectSplit_imp (T& retval, std::index_sequence, const int * src) noexcept { + (IntVectSplit_imp2(std::get(retval), src), ...); + return retval; + } + + template + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE constexpr + int get_sum () { + return (0 + ... + dims); + } +} + +template +std::ostream& +operator<< (std::ostream& os, const IntVectND& iv) +{ + return detail::int_vector_write(os, iv.begin(), dim); +} + +template +std::istream& +operator>> (std::istream& is, IntVectND& iv) +{ + return detail::int_vector_read(is, iv.begin(), dim); +} + +/** +* \brief Returns a IntVectND obtained by concatenating the input IntVectNDs. +* The dimension of the return value equals the sum of the dimensions of the inputted IntVectNDs. +*/ +template +AMREX_GPU_HOST_DEVICE +AMREX_FORCE_INLINE +constexpr IntVectND()> +IntVectCat (const IntVectND& v, const IntVectND&...vects) noexcept { + IntVectND()> retval (0); + int* dst = retval.begin(); + detail::IntVectCat_imp(dst, v); + (detail::IntVectCat_imp(dst, vects), ...); + return retval; +} + +/** +* \brief Returns a tuple of IntVectND obtained by splitting the input IntVectND +* according to the dimensions specified by the template arguments. +*/ +template +AMREX_GPU_HOST_DEVICE +AMREX_FORCE_INLINE +constexpr GpuTuple, IntVectND...> +IntVectSplit (const IntVectND()>& v) noexcept { + GpuTuple, IntVectND...> retval; + return detail::IntVectSplit_imp(retval, + std::make_index_sequence<1 + sizeof...(dims)>(), + v.begin()); } +/** +* \brief Returns a new IntVectND of size new_dim and +* assigns the first new_dim values of iv to it. +*/ +template +AMREX_GPU_HOST_DEVICE +AMREX_FORCE_INLINE +constexpr IntVectND +IntVectShrink (const IntVectND& iv) noexcept { + return iv.template shrink(); +} + +/** +* \brief Returns a new IntVectND of size new_dim and +* assigns all values of iv to it andĀ fill_extra to the remaining elements. +*/ +template +AMREX_GPU_HOST_DEVICE +AMREX_FORCE_INLINE +constexpr IntVectND +IntVectExpand (const IntVectND& iv, int fill_extra=0) noexcept { + return iv.template expand(fill_extra); +} + +/** +* \brief Returns a new IntVectND of size new_dim +* by either shrinking or expanding iv. +*/ +template +AMREX_GPU_HOST_DEVICE +AMREX_FORCE_INLINE +constexpr IntVectND +IntVectResize (const IntVectND& iv, int fill_extra=0) noexcept { + return iv.template resize(fill_extra); +} + +} // namespace amrex + +// Spcialize std::tuple_size for IntVectND. Used by structured bindings. +template +struct std::tuple_size> { + static constexpr std::size_t value = dim; +}; + +// Spcialize std::tuple_element for IntVectND. Used by structured bindings. +template +struct std::tuple_element> { + using type = int; +}; + #endif /*AMREX_INTVECT_H*/ diff --git a/Src/Base/AMReX_IntVect.cpp b/Src/Base/AMReX_IntVect.cpp index 5e68f633d19..e61bec6497c 100644 --- a/Src/Base/AMReX_IntVect.cpp +++ b/Src/Base/AMReX_IntVect.cpp @@ -7,17 +7,16 @@ #include -namespace amrex { - -const IntVect IntVect::Zero = IntVect::TheZeroVector(); -const IntVect IntVect::Unit = IntVect::TheUnitVector(); +namespace amrex::detail { std::ostream& -operator<< (std::ostream& os, const IntVect& iv) +int_vector_write (std::ostream& os, const int* iv, int dim) { - os << AMREX_D_TERM( '(' << iv[0] , << - ',' << iv[1] , << - ',' << iv[2]) << ')'; + os << '(' << iv[0]; + for (int i=1; i> (std::istream& is, IntVect& iv) +int_vector_read (std::istream& is, int* iv, int dim) { is >> std::ws; char c; is >> c; - AMREX_D_TERM(iv[0]=0;, iv[1]=0;, iv[2]=0); + for (int i=0; i> iv[0]; -#if (AMREX_SPACEDIM >= 2) - is >> std::ws; - int ic = is.peek(); - if (ic == static_cast(',')) { - is.ignore(BL_IGNORE_MAX, ','); - is >> iv[1]; -#if (AMREX_SPACEDIM == 3) + for (int i=1; i> std::ws; - ic = is.peek(); + int ic = is.peek(); if (ic == static_cast(',')) { is.ignore(BL_IGNORE_MAX, ','); - is >> iv[2]; + is >> iv[i]; + continue; } -#endif + break; } -#endif is.ignore(BL_IGNORE_MAX, ')'); } else diff --git a/Src/Base/AMReX_ParmParse.H b/Src/Base/AMReX_ParmParse.H index 062db374029..11524eca689 100644 --- a/Src/Base/AMReX_ParmParse.H +++ b/Src/Base/AMReX_ParmParse.H @@ -17,7 +17,9 @@ namespace amrex { class Box; -class IntVect; +template +class IntVectND; +using IntVect = IntVectND; // // ParmParse class implements a simple database for the storage and diff --git a/Src/Base/AMReX_TypeTraits.H b/Src/Base/AMReX_TypeTraits.H index 2e4985bf224..d2960b11c57 100644 --- a/Src/Base/AMReX_TypeTraits.H +++ b/Src/Base/AMReX_TypeTraits.H @@ -238,6 +238,29 @@ namespace amrex using Negation = std::integral_constant; #endif + //////////////////////////////////////////////////////////////////////////////// + // [traits.IsConvertible] + + namespace detail { + template + inline constexpr bool is_convertible(T) {return true;} + + template + struct IsConvertibleImp : std::false_type {}; + + template + struct IsConvertibleImp(U{})>> : std::true_type {}; + } + + //! \brief Test if all the types Args... are automatically convertible to type T + template + struct IsConvertible { + static constexpr bool value = (... && detail::IsConvertibleImp::value); + }; + + template + inline constexpr bool IsConvertible_v = IsConvertible::value; + // Move this down, because doxygen can not parse anything below IsStoreAtomic template struct IsStoreAtomic : std::false_type {};