HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
recursive_iterator.hpp
1// Copyright Take Vos 2020-2021.
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 hi {
12inline namespace v1 {
13
18template<typename ParentIt>
20 using parent_iterator = ParentIt;
21 using child_iterator = std::conditional_t<
22 std::is_const_v<std::remove_reference_t<typename std::iterator_traits<ParentIt>::reference>>,
25
26 using value_type = typename std::iterator_traits<child_iterator>::value_type;
27 using difference_type = typename std::iterator_traits<child_iterator>::difference_type;
28 using reference = typename std::iterator_traits<child_iterator>::reference;
29 using pointer = typename std::iterator_traits<child_iterator>::pointer;
30
31public:
32 constexpr recursive_iterator() noexcept = delete;
33 constexpr recursive_iterator(recursive_iterator const& other) noexcept = default;
34 constexpr recursive_iterator(recursive_iterator&& other) noexcept = default;
35 constexpr recursive_iterator& operator=(recursive_iterator const& other) noexcept = default;
36 constexpr recursive_iterator& operator=(recursive_iterator&& other) noexcept = default;
37 ~recursive_iterator() = default;
38
41 constexpr recursive_iterator(parent_iterator parent_it, parent_iterator parent_it_end, child_iterator child_it) noexcept :
42 _parent_it(parent_it), _parent_it_end(parent_it_end), _child_it(child_it)
43 {
44 }
45
48 constexpr recursive_iterator(parent_iterator parent_it, parent_iterator parent_it_end) noexcept :
49 _parent_it(parent_it),
50 _parent_it_end(parent_it_end),
51 _child_it(parent_it != parent_it_end ? std::begin(*parent_it) : child_iterator{})
52 {
53 }
54
57 constexpr recursive_iterator(parent_iterator parent_it_end) noexcept :
58 _parent_it(parent_it_end), _parent_it_end(parent_it_end), _child_it()
59 {
60 }
61
64 [[nodiscard]] constexpr parent_iterator parent() const noexcept
65 {
66 return _parent_it;
67 }
68
72 [[nodiscard]] constexpr child_iterator child() const noexcept
73 {
74 hi_axiom(!at_end());
75 return _child_it;
76 }
77
85 [[nodiscard]] constexpr bool at_end() const noexcept
86 {
87 return _parent_it == _parent_it_end;
88 }
89
90 [[nodiscard]] constexpr reference operator*() const noexcept
91 {
92 return *_child_it;
93 }
94
95 [[nodiscard]] constexpr pointer operator->() const noexcept
96 {
97 return &(*_child_it);
98 }
99
100 [[nodiscard]] constexpr reference operator[](std::size_t i) const noexcept
101 {
102 return *(*this + i);
103 }
104
105 constexpr recursive_iterator& operator++() noexcept
106 {
107 ++_child_it;
108 if (_child_it == std::end(*_parent_it)) {
109 ++_parent_it;
110 if (!at_end()) {
111 _child_it = _parent_it->begin();
112 }
113 }
114 return *this;
115 }
116
117 constexpr recursive_iterator& operator--() noexcept
118 {
119 if (_child_it == std::begin(*_parent_it)) {
120 --_parent_it;
121 _child_it = std::end(*_parent_it);
122 }
123 --_child_it;
124 return *this;
125 }
126
127 constexpr recursive_iterator operator++(int) noexcept
128 {
129 auto tmp = *this;
130 ++(*this);
131 return tmp;
132 }
133
134 constexpr recursive_iterator operator--(int) noexcept
135 {
136 auto tmp = *this;
137 --(*this);
138 return tmp;
139 }
140
141 constexpr recursive_iterator& operator+=(difference_type rhs) noexcept
142 {
143 if (rhs < 0) {
144 return (*this) -= -rhs;
145 }
146
147 do {
148 hilet left_in_child = std::distance(_child_it, std::end(*_parent_it));
149
150 if (left_in_child <= rhs) {
151 ++_parent_it;
152 if (!at_end()) {
153 _child_it = std::begin(*_parent_it);
154 }
155 rhs -= left_in_child;
156
157 } else {
158 _child_it += rhs;
159 rhs -= rhs;
160 }
161
162 } while (rhs);
163
164 return *this;
165 }
166
167 constexpr recursive_iterator& operator-=(difference_type rhs) noexcept
168 {
169 if (rhs < 0) {
170 return (*this) += -rhs;
171 }
172
173 do {
174 hilet left_in_child = !at_end() ? std::distance(std::begin(*_parent_it), _child_it) + 1 : 0;
175
176 if (left_in_child < rhs) {
177 --_parent_it;
178 _child_it = std::end(*_parent_it) - 1;
179 rhs -= (left_in_child + 1);
180
181 } else {
182 _child_it -= rhs;
183 rhs -= rhs;
184 }
185
186 } while (rhs);
187
188 return *this;
189 }
190
191 [[nodiscard]] constexpr friend bool operator==(recursive_iterator const& lhs, recursive_iterator const& rhs) noexcept
192 {
193 if (lhs._parent_it != rhs._parent_it) {
194 return false;
195 } else if (lhs.at_end()) {
196 hi_axiom(rhs.at_end());
197 return true;
198 } else {
199 return lhs._child_it == rhs._child_it;
200 }
201 }
202
203 [[nodiscard]] constexpr friend std::strong_ordering
204 operator<=>(recursive_iterator const& lhs, recursive_iterator const& rhs) noexcept
205 {
206 if (lhs._parent_it != rhs._parent_it) {
207 return (lhs._parent_it - rhs._parent_it) <=> 0;
208 } else if (lhs.at_end()) {
209 hi_axiom(rhs.at_end());
210 return std::strong_ordering::equal;
211 } else {
212 return (lhs._child_it - rhs._child_it) <=> 0;
213 }
214 }
215
216 [[nodiscard]] constexpr friend recursive_iterator operator+(recursive_iterator lhs, difference_type rhs) noexcept
217 {
218 return lhs += rhs;
219 }
220 [[nodiscard]] constexpr friend recursive_iterator operator-(recursive_iterator lhs, difference_type rhs) noexcept
221 {
222 return lhs -= rhs;
223 }
224 [[nodiscard]] constexpr friend recursive_iterator operator+(difference_type lhs, recursive_iterator rhs) noexcept
225 {
226 return rhs += lhs;
227 }
228
229 [[nodiscard]] constexpr friend difference_type
230 operator-(recursive_iterator const& lhs, recursive_iterator const& rhs) noexcept
231 {
232 if (rhs < lhs) {
233 return -(rhs - lhs);
234 } else {
235 auto lhs_ = lhs;
236 difference_type count = 0;
237 while (lhs_._parent_it < rhs._parent_it) {
238 count += std::distance(lhs_.child_it, std::end(*lhs_._parent_it));
239 ++(lhs_._parent_it);
240 lhs_._child_it = begin(*lhs_._parent_it);
241 }
242 return count + std::distance(lhs_._child_it, rhs._child_it);
243 }
244 }
245
246private:
247 parent_iterator _parent_it;
248 parent_iterator _parent_it_end;
249 child_iterator _child_it;
250};
251
254template<typename Container>
255[[nodiscard]] constexpr auto recursive_iterator_begin(Container& rhs) noexcept
256{
257 return recursive_iterator(begin(rhs), end(rhs));
258}
259
262template<typename Container>
263[[nodiscard]] constexpr auto recursive_iterator_end(Container& rhs) noexcept
264{
265 return recursive_iterator(end(rhs), end(rhs));
266}
267
270template<typename Container>
271[[nodiscard]] constexpr auto recursive_iterator_begin(Container const& rhs) noexcept
272{
273 return recursive_iterator(begin(rhs), end(rhs));
274}
275
278template<typename Container>
279[[nodiscard]] constexpr auto recursive_iterator_end(Container const& rhs) noexcept
280{
281 return recursive_iterator(end(rhs), end(rhs));
282}
283
284}} // namespace hi::inline v1
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:253
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
@ end
Start from the end of the file.
@ begin
Start from the beginning of the file.
@ other
The gui_event does not have associated data.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
constexpr auto recursive_iterator_begin(Container &rhs) noexcept
Get a recursive iterator from the begin of a recursive container.
Definition recursive_iterator.hpp:255
constexpr auto recursive_iterator_end(Container &rhs) noexcept
Get a recursive iterator from one beyond the end of a recursive container.
Definition recursive_iterator.hpp:263
An iterator which recursively iterates through nested containers.
Definition recursive_iterator.hpp:19
constexpr child_iterator child() const noexcept
Get the current child iterator.
Definition recursive_iterator.hpp:72
constexpr 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:41
constexpr bool at_end() const noexcept
Check if the iterator is at end.
Definition recursive_iterator.hpp:85
constexpr recursive_iterator(parent_iterator parent_it_end) noexcept
Create an end iterator one beyond the last child.
Definition recursive_iterator.hpp:57
constexpr 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:48
constexpr parent_iterator parent() const noexcept
Get the current parent iterator.
Definition recursive_iterator.hpp:64
T begin(T... args)
T count(T... args)
T distance(T... args)
T end(T... args)