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