Line data Source code
1 1 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : /// \file 5 : /// Defines class template Index. 6 : 7 : #pragma once 8 : 9 : #include <array> 10 : #include <cstddef> 11 : #include <limits> 12 : #include <ostream> 13 : 14 : #include "Utilities/ErrorHandling/Assert.hpp" 15 : #include "Utilities/ForceInline.hpp" 16 : #include "Utilities/Gsl.hpp" 17 : #include "Utilities/MakeArray.hpp" 18 : #include "Utilities/Requires.hpp" 19 : #include "Utilities/TypeTraits.hpp" // IWYU pragma: keep 20 : #include "Utilities/TypeTraits/IsInteger.hpp" 21 : 22 : namespace PUP { 23 : class er; 24 : } // namespace PUP 25 : 26 : /// \ingroup DataStructuresGroup 27 : /// An integer multi-index. 28 : /// 29 : /// \tparam Dim the number of integers in the Index. 30 : template <size_t Dim> 31 1 : class Index { 32 : public: 33 : /// Construct with each element set to the same value. 34 1 : explicit Index(const size_t i0 = std::numeric_limits<size_t>::max()) 35 : : indices_(make_array<Dim>(i0)) {} 36 : 37 : /// Construct specifying value in each dimension 38 : template <typename... I, Requires<(sizeof...(I) > 1)> = nullptr> 39 1 : explicit Index(I... i) : indices_(make_array(static_cast<size_t>(i)...)) { 40 : static_assert(std::conjunction_v<tt::is_integer<I>...>, 41 : "You must pass in a set of size_t's to Index."); 42 : static_assert(Dim == sizeof...(I), 43 : "The number of indices given to Index must be the same as " 44 : "the dimensionality of the Index."); 45 : } 46 : 47 0 : explicit Index(std::array<size_t, Dim> i) : indices_(std::move(i)) {} 48 : 49 0 : size_t operator[](const size_t d) const { return gsl::at(indices_, d); } 50 0 : size_t& operator[](const size_t d) { return gsl::at(indices_, d); } 51 : 52 0 : typename std::array<size_t, Dim>::iterator begin() { 53 : return indices_.begin(); 54 : } 55 0 : typename std::array<size_t, Dim>::const_iterator begin() const { 56 : return indices_.begin(); 57 : } 58 : 59 0 : typename std::array<size_t, Dim>::iterator end() { return indices_.end(); } 60 0 : typename std::array<size_t, Dim>::const_iterator end() const { 61 : return indices_.end(); 62 : } 63 : 64 0 : size_t size() const { return Dim; } 65 : 66 : /// The product of the indices. 67 : /// If Dim = 0, the product is defined as 1. 68 : template <int N = Dim, Requires<(N > 0)> = nullptr> 69 1 : constexpr size_t product() const { 70 : return indices_[N - 1] * product<N - 1>(); 71 : } 72 : /// \cond 73 : // Specialization for N = 0 to stop recursion 74 : template <int N = Dim, Requires<(N == 0)> = nullptr> 75 : constexpr size_t product() const { 76 : return 1; 77 : } 78 : /// \endcond 79 : 80 : /// Return a smaller Index with the d-th element removed. 81 : /// 82 : /// \param d the element to remove. 83 : template <size_t N = Dim, Requires<(N > 0)> = nullptr> 84 1 : Index<Dim - 1> slice_away(const size_t d) const { 85 : ASSERT(d < Dim, 86 : "Can't slice dimension " << d << " from an Index<" << Dim << ">"); 87 : std::array<size_t, Dim - 1> t{}; 88 : for (size_t i = 0; i < Dim; ++i) { 89 : if (i < d) { 90 : gsl::at(t, i) = gsl::at(indices_, i); 91 : } else if (i > d) { 92 : gsl::at(t, i - 1) = gsl::at(indices_, i); 93 : } 94 : } 95 : return Index<Dim - 1>(t); 96 : } 97 : 98 : /// \cond 99 : // NOLINTNEXTLINE(google-runtime-references) 100 : void pup(PUP::er& p); 101 : /// \endcond 102 : 103 : template <size_t N> 104 0 : friend std::ostream& operator<<(std::ostream& os, // NOLINT 105 : const Index<N>& i); 106 : 107 0 : const size_t* data() const { return indices_.data(); } 108 0 : size_t* data() { return indices_.data(); } 109 : 110 0 : const std::array<size_t, Dim>& indices() const { return indices_; } 111 : 112 : private: 113 0 : std::array<size_t, Dim> indices_; 114 : }; 115 : 116 : /// \ingroup DataStructuresGroup 117 : /// Get the collapsed index into a 1D array of the data corresponding to this 118 : /// Index. Note that the first dimension of the Index varies fastest when 119 : /// computing the collapsed index. 120 : template <size_t N> 121 1 : size_t collapsed_index(const Index<N>& index, const Index<N>& extents); 122 : 123 : template <size_t N> 124 0 : std::ostream& operator<<(std::ostream& os, const Index<N>& i); 125 : 126 : /// \cond HIDDEN_SYMBOLS 127 : #ifdef SPECTRE_DEBUG 128 : namespace Index_detail { 129 : template <size_t Dim> 130 : void collapsed_index_check(const Index<Dim>& index, const Index<Dim>& extents) { 131 : for (size_t d = 0; d < Dim; ++d) { 132 : ASSERT(index[d] < extents[d], "The requested index in the dimension " 133 : << d << " with value " << index[d] 134 : << " exceeds the number of grid " 135 : "points " 136 : << extents[d]); 137 : } 138 : } 139 : } // namespace Index_detail 140 : #endif 141 : 142 : // the specializations are in the header file so they can be inlined. We use 143 : // specializations to avoid having loops since this computation is very 144 : // straightforward. 145 : template <> 146 : SPECTRE_ALWAYS_INLINE size_t collapsed_index(const Index<0>& /*index*/, 147 : const Index<0>& /*extents*/) { 148 : return 0; 149 : } 150 : 151 : template <> 152 : SPECTRE_ALWAYS_INLINE size_t collapsed_index(const Index<1>& index, 153 : const Index<1>& extents) { 154 : (void)extents; 155 : #ifdef SPECTRE_DEBUG 156 : Index_detail::collapsed_index_check(index, extents); 157 : #endif 158 : return index[0]; 159 : } 160 : 161 : template <> 162 : SPECTRE_ALWAYS_INLINE size_t collapsed_index(const Index<2>& index, 163 : const Index<2>& extents) { 164 : #ifdef SPECTRE_DEBUG 165 : Index_detail::collapsed_index_check(index, extents); 166 : #endif 167 : return index[0] + extents[0] * index[1]; 168 : } 169 : 170 : template <> 171 : SPECTRE_ALWAYS_INLINE size_t collapsed_index(const Index<3>& index, 172 : const Index<3>& extents) { 173 : #ifdef SPECTRE_DEBUG 174 : Index_detail::collapsed_index_check(index, extents); 175 : #endif 176 : return index[0] + extents[0] * (index[1] + extents[1] * index[2]); 177 : } 178 : 179 : template <> 180 : SPECTRE_ALWAYS_INLINE size_t collapsed_index(const Index<4>& index, 181 : const Index<4>& extents) { 182 : #ifdef SPECTRE_DEBUG 183 : Index_detail::collapsed_index_check(index, extents); 184 : #endif 185 : return index[0] + 186 : extents[0] * 187 : (index[1] + extents[1] * (index[2] + extents[2] * index[3])); 188 : } 189 : 190 : template <size_t N> 191 : bool operator==(const Index<N>& lhs, const Index<N>& rhs); 192 : 193 : template <size_t N> 194 : bool operator!=(const Index<N>& lhs, const Index<N>& rhs); 195 : /// \endcond