HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
recursive_iterator.hpp
1// Copyright Take Vos 2020.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include <type_traits>
8#include <compare>
9#include <iterator>
10
11namespace tt {
12
17template<typename ParentIt>
19 using parent_iterator = ParentIt;
20 using child_iterator = std::conditional_t<
21 std::is_const_v<std::remove_reference_t<typename std::iterator_traits<ParentIt>::reference>>,
24
25 using value_type = typename std::iterator_traits<child_iterator>::value_type;
26 using difference_type = typename std::iterator_traits<child_iterator>::difference_type;
29
30public:
31 recursive_iterator() noexcept = delete;
32 recursive_iterator(recursive_iterator const &other) noexcept = default;
33 recursive_iterator(recursive_iterator &&other) noexcept = default;
34 recursive_iterator &operator=(recursive_iterator const &other) noexcept = default;
35 recursive_iterator &operator=(recursive_iterator &&other) noexcept = default;
36 ~recursive_iterator() = default;
37
40 recursive_iterator(parent_iterator parent_it, parent_iterator parent_it_end, child_iterator child_it) noexcept :
41 _parent_it(parent_it), _parent_it_end(parent_it_end), _child_it(child_it)
42 {
43 }
44
47 recursive_iterator(parent_iterator parent_it, parent_iterator parent_it_end) noexcept :
48 _parent_it(parent_it),
49 _parent_it_end(parent_it_end),
50 _child_it(parent_it != parent_it_end ? std::begin(*parent_it) : child_iterator{})
51 {
52 }
53
56 recursive_iterator(parent_iterator parent_it_end) noexcept :
57 _parent_it(parent_it_end), _parent_it_end(parent_it_end), _child_it()
58 {
59 }
60
63 [[nodiscard]] parent_iterator parent() const noexcept
64 {
65 return _parent_it;
66 }
67
71 [[nodiscard]] child_iterator child() const noexcept
72 {
73 tt_axiom(!at_end());
74 return _child_it;
75 }
76
84 [[nodiscard]] bool at_end() const noexcept
85 {
86 return _parent_it == _parent_it_end;
87 }
88
89 [[nodiscard]] reference operator*() const noexcept
90 {
91 return *_child_it;
92 }
93
94 [[nodiscard]] pointer operator->() const noexcept
95 {
96 return &(*_child_it);
97 }
98
99 [[nodiscard]] reference operator[](size_t i) const noexcept
100 {
101 return *(*this + i);
102 }
103
104 recursive_iterator &operator++() noexcept
105 {
106 ++_child_it;
107 if (_child_it == std::end(*_parent_it)) {
108 ++_parent_it;
109 if (!at_end()) {
110 _child_it = _parent_it->begin();
111 }
112 }
113 return *this;
114 }
115
116 recursive_iterator &operator--() noexcept
117 {
118 if (_child_it == std::begin(*_parent_it)) {
119 --_parent_it;
120 _child_it = std::end(*_parent_it);
121 }
122 --_child_it;
123 return *this;
124 }
125
126 recursive_iterator operator++(int) noexcept
127 {
128 auto tmp = *this;
129 ++(*this);
130 return tmp;
131 }
132 recursive_iterator operator--(int) noexcept
133 {
134 auto tmp = *this;
135 --(*this);
136 return tmp;
137 }
138
139 recursive_iterator &operator+=(difference_type rhs) noexcept
140 {
141 if (rhs < 0) {
142 return (*this) -= -rhs;
143 }
144
145 do {
146 ttlet left_in_child = std::distance(_child_it, std::end(*_parent_it));
147
148 if (left_in_child <= rhs) {
149 ++_parent_it;
150 if (!at_end()) {
151 _child_it = std::begin(*_parent_it);
152 }
153 rhs -= left_in_child;
154
155 } else {
156 _child_it += rhs;
157 rhs -= rhs;
158 }
159
160 } while (rhs);
161
162 return *this;
163 }
164
165 recursive_iterator &operator-=(difference_type rhs) noexcept
166 {
167 if (rhs < 0) {
168 return (*this) += -rhs;
169 }
170
171 do {
172 ttlet left_in_child = !at_end() ? std::distance(std::begin(*_parent_it), _child_it) + 1 : 0;
173
174 if (left_in_child < rhs) {
175 --_parent_it;
176 _child_it = std::end(*_parent_it) - 1;
177 rhs -= (left_in_child + 1);
178
179 } else {
180 _child_it -= rhs;
181 rhs -= rhs;
182 }
183
184 } while (rhs);
185
186 return *this;
187 }
188
189 [[nodiscard]] friend bool operator==(recursive_iterator const &lhs, recursive_iterator const &rhs) noexcept
190 {
191 if (lhs._parent_it != rhs._parent_it) {
192 return false;
193 } else if (lhs.at_end()) {
194 tt_axiom(rhs.at_end());
195 return true;
196 } else {
197 return lhs._child_it == rhs._child_it;
198 }
199 }
200
201 [[nodiscard]] friend std::strong_ordering
202 operator<=>(recursive_iterator const &lhs, recursive_iterator const &rhs) noexcept
203 {
204 if (lhs._parent_it != rhs._parent_it) {
205 return (lhs._parent_it - rhs._parent_it) <=> 0;
206 } else if (lhs.at_end()) {
207 tt_axiom(rhs.at_end());
208 return std::strong_ordering::equal;
209 } else {
210 return (lhs._child_it - rhs._child_it) <=> 0;
211 }
212 }
213
214 [[nodiscard]] friend recursive_iterator operator+(recursive_iterator lhs, difference_type rhs) noexcept
215 {
216 return lhs += rhs;
217 }
218 [[nodiscard]] friend recursive_iterator operator-(recursive_iterator lhs, difference_type rhs) noexcept
219 {
220 return lhs -= rhs;
221 }
222 [[nodiscard]] friend recursive_iterator operator+(difference_type lhs, recursive_iterator rhs) noexcept
223 {
224 return rhs += lhs;
225 }
226
227 [[nodiscard]] friend difference_type operator-(recursive_iterator const &lhs, recursive_iterator const &rhs) noexcept
228 {
229 if (rhs < lhs) {
230 return -(rhs - lhs);
231 } else {
232 auto lhs_ = lhs;
233 difference_type count = 0;
234 while (lhs_._parent_it < rhs._parent_it) {
235 count += std::distance(lhs_.child_it, std::end(*lhs_._parent_it));
236 ++(lhs_._parent_it);
237 lhs_._child_it = std::begin(*lhs_._parent_it);
238 }
239 return count + std::distance(lhs_._child_it, rhs._child_it);
240 }
241 }
242
243private:
244 parent_iterator _parent_it;
245 parent_iterator _parent_it_end;
246 child_iterator _child_it;
247};
248
251template<typename Container>
252[[nodiscard]] auto recursive_iterator_begin(Container &rhs) noexcept
253{
254 return recursive_iterator(std::begin(rhs), std::end(rhs));
255}
256
259template<typename Container>
260[[nodiscard]] auto recursive_iterator_end(Container &rhs) noexcept
261{
262 return recursive_iterator(std::end(rhs), std::end(rhs));
263}
264
267template<typename Container>
268[[nodiscard]] auto recursive_iterator_begin(Container const &rhs) noexcept
269{
270 return recursive_iterator(std::begin(rhs), std::end(rhs));
271}
272
275template<typename Container>
276[[nodiscard]] auto recursive_iterator_end(Container const &rhs) noexcept
277{
278 return recursive_iterator(std::end(rhs), std::end(rhs));
279}
280
281} // namespace tt
An iterator which recursively iterates through nested containers.
Definition recursive_iterator.hpp:18
recursive_iterator(parent_iterator parent_it, parent_iterator parent_it_end, child_iterator child_it) noexcept
Create an iterator at an element inside a child container.
Definition recursive_iterator.hpp:40
bool at_end() const noexcept
Check if the iterator is at end.
Definition recursive_iterator.hpp:84
recursive_iterator(parent_iterator parent_it_end) noexcept
Create an end iterator one beyond the last child.
Definition recursive_iterator.hpp:56
parent_iterator parent() const noexcept
Get the current parent iterator.
Definition recursive_iterator.hpp:63
recursive_iterator(parent_iterator parent_it, parent_iterator parent_it_end) noexcept
Create a begin iterator at the first child's first element.
Definition recursive_iterator.hpp:47
child_iterator child() const noexcept
Get the current child iterator.
Definition recursive_iterator.hpp:71
Definition concepts.hpp:18
Definition concepts.hpp:21
T begin(T... args)
T count(T... args)
T distance(T... args)
T end(T... args)