Line data Source code
1 : #pragma once 2 : 3 : #include <cstddef> 4 : #include <iterator> 5 : 6 : namespace pa { 7 : 8 : template <class IndexT = size_t> 9 : struct CircularIndices { 10 : using Index = IndexT; 11 83 : CircularIndices(Index zerobased, Index circular) 12 83 : : zerobased(zerobased), circular(circular) {} 13 : Index zerobased; 14 : Index circular; 15 : }; 16 : /// @related CircularIndices 17 : /// @note Only valid for two indices in the same range. 18 : template <class IndexT> 19 235 : bool operator==(CircularIndices<IndexT> a, CircularIndices<IndexT> b) { 20 235 : return a.zerobased == b.zerobased; 21 : } 22 : /// @related CircularIndices 23 : /// @note Only valid for two indices in the same range. 24 : template <class IndexT> 25 : bool operator!=(CircularIndices<IndexT> a, CircularIndices<IndexT> b) { 26 : return !(a == b); 27 : } 28 : 29 : template <class IndexT = size_t> 30 : struct CircularIndexIterator { 31 : using Index = IndexT; 32 : using Indices = CircularIndices<Index>; 33 : 34 : CircularIndexIterator() : i{0, 0}, max{0} {} 35 166 : CircularIndexIterator(Indices i, Index max) : i(i), max(max) {} 36 : 37 : Indices i; 38 : Index max; 39 : 40 : using value_type = Indices; 41 : using reference = value_type; 42 : using difference_type = std::ptrdiff_t; // This is required but not used 43 : using pointer = void; 44 : using iterator_category = std::input_iterator_tag; 45 : 46 338 : reference operator*() const { return i; } 47 95 : CircularIndexIterator &operator++() { 48 95 : assert(i.zerobased < max); 49 95 : ++i.zerobased; 50 95 : i.circular = i.circular + 1 == max ? Index{0} : i.circular + 1; 51 95 : return *this; 52 : } 53 152 : CircularIndexIterator &operator--() { 54 152 : assert(i.zerobased > 0); 55 152 : --i.zerobased; 56 152 : i.circular = i.circular == Index{0} ? max - 1 : i.circular - 1; 57 152 : return *this; 58 : } 59 1 : CircularIndexIterator operator++(int) { 60 1 : auto r = *this; 61 1 : ++(*this); 62 1 : return r; 63 : } 64 : CircularIndexIterator operator--(int) { 65 : auto r = *this; 66 : --(*this); 67 : return r; 68 : } 69 : }; 70 : 71 : /// @related CircularIndexIterator 72 : /// @note Only valid for two indices in the same range. 73 : template <class IndexT> 74 234 : bool operator==(CircularIndexIterator<IndexT> a, 75 : CircularIndexIterator<IndexT> b) { 76 234 : assert(a.max == b.max); 77 234 : return a.i == b.i; 78 : } 79 : /// @related CircularIndexIterator 80 : /// @note Only valid for two indices in the same range. 81 : template <class IndexT> 82 135 : bool operator!=(CircularIndexIterator<IndexT> a, 83 : CircularIndexIterator<IndexT> b) { 84 135 : return !(a == b); 85 : } 86 : 87 : template <class IndexT = size_t> 88 : struct ReverseCircularIndexIterator { 89 : using ForwardIterator = CircularIndexIterator<IndexT>; 90 : using Index = typename ForwardIterator::Index; 91 : using Indices = typename ForwardIterator::Indices; 92 : 93 : ReverseCircularIndexIterator() : forwardit() {} 94 : ReverseCircularIndexIterator(Indices i, Index max) : forwardit(i, max) {} 95 40 : ReverseCircularIndexIterator(ForwardIterator forwardit) 96 40 : : forwardit(forwardit) {} 97 : 98 : ForwardIterator forwardit; 99 : 100 : using value_type = Indices; 101 : using reference = value_type; 102 : using difference_type = std::ptrdiff_t; // This is required but not used 103 : using pointer = void; 104 : using iterator_category = std::input_iterator_tag; 105 : 106 76 : reference operator*() const { 107 76 : auto tmp = forwardit; 108 76 : return *(--tmp); 109 76 : } 110 76 : ReverseCircularIndexIterator &operator++() { 111 76 : --forwardit; 112 76 : return *this; 113 : } 114 : ReverseCircularIndexIterator &operator--() { 115 : ++forwardit; 116 : return *this; 117 : } 118 : ReverseCircularIndexIterator operator++(int) { 119 : auto r = *this; 120 : ++(*this); 121 : return r; 122 : } 123 : ReverseCircularIndexIterator operator--(int) { 124 : auto r = *this; 125 : --(*this); 126 : return r; 127 : } 128 : }; 129 : 130 : /// @related ReverseCircularIndexIterator 131 : /// @note Only valid for two indices in the same range. 132 : template <class IndexT> 133 96 : bool operator==(ReverseCircularIndexIterator<IndexT> a, 134 : ReverseCircularIndexIterator<IndexT> b) { 135 96 : return a.forwardit == b.forwardit; 136 : } 137 : /// @related ReverseCircularIndexIterator 138 : /// @note Only valid for two indices in the same range. 139 : template <class IndexT> 140 96 : bool operator!=(ReverseCircularIndexIterator<IndexT> a, 141 : ReverseCircularIndexIterator<IndexT> b) { 142 96 : return !(a == b); 143 : } 144 : 145 : template <class IndexT> 146 : class CircularRange { 147 : public: 148 : using Index = IndexT; 149 : using Indices = CircularIndices<Index>; 150 : 151 46 : CircularRange(Index size, Index idx1, Index idx2, Index max) 152 46 : : size(size), idx1(idx1), idx2(idx2), max(max) {} 153 : 154 : using const_iterator = CircularIndexIterator<Index>; 155 : using iterator = const_iterator; 156 : 157 : using const_reverse_iterator = ReverseCircularIndexIterator<Index>; 158 : using reverse_iterator = const_reverse_iterator; 159 : 160 76 : iterator begin() const { return {{Index{0}, idx1}, max}; } 161 90 : iterator end() const { return {{size, idx2}, max}; } 162 : const_iterator cbegin() const { return begin(); } 163 : const_iterator cend() const { return end(); } 164 : 165 40 : reverse_iterator rbegin() const { return reverse_iterator{end()}; } 166 40 : reverse_iterator rend() const { return reverse_iterator{begin()}; } 167 : const_reverse_iterator crbegin() const { 168 : return const_reverse_iterator{end()}; 169 : } 170 : const_reverse_iterator crend() const { 171 : return const_reverse_iterator{begin()}; 172 : } 173 : 174 : private: 175 : Index size; 176 : Index idx1, idx2; 177 : Index max; 178 : }; 179 : 180 : template <class IndexT> 181 : class ReverseCircularRange { 182 : public: 183 : using ForwardRange = CircularRange<IndexT>; 184 : using Index = typename ForwardRange::Index; 185 : using Indices = typename ForwardRange::Indices; 186 : 187 16 : ReverseCircularRange(const ForwardRange &forwardrange) 188 16 : : forwardrange(forwardrange) {} 189 6 : ReverseCircularRange(Index size, Index idx1, Index idx2, Index max) 190 6 : : forwardrange(size, idx1, idx2, max) {} 191 : 192 : using const_iterator = typename ForwardRange::const_reverse_iterator; 193 : using iterator = typename ForwardRange::reverse_iterator; 194 : 195 : using const_reverse_iterator = typename ForwardRange::const_iterator; 196 : using reverse_iterator = typename ForwardRange::iterator; 197 : 198 28 : iterator begin() const { return forwardrange.rbegin(); } 199 28 : iterator end() const { return forwardrange.rend(); } 200 : const_iterator cbegin() const { return forwardrange.crbegin(); } 201 : const_iterator cend() const { return forwardrange.crend(); } 202 : 203 12 : reverse_iterator rbegin() const { return forwardrange.begin(); } 204 12 : reverse_iterator rend() const { return forwardrange.end(); } 205 : const_reverse_iterator crbegin() const { return forwardrange.cbegin(); } 206 : const_reverse_iterator crend() const { return forwardrange.cend(); } 207 : 208 : private: 209 : ForwardRange forwardrange; 210 : }; 211 : 212 : } // namespace pa