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 "../utility/utility.hpp"
8#include "../macros.hpp"
9#include <type_traits>
10#include <compare>
11#include <iterator>
12
13hi_export_module(hikogui.algorithm.recursive_iterator);
14
15hi_export namespace hi {
16inline namespace v1 {
17
22template<typename ParentIt>
24 using parent_iterator = ParentIt;
25 using child_iterator = std::conditional_t<
26 std::is_const_v<std::remove_reference_t<typename std::iterator_traits<ParentIt>::reference>>,
29
30 using value_type = typename std::iterator_traits<child_iterator>::value_type;
31 using difference_type = typename std::iterator_traits<child_iterator>::difference_type;
32 using reference = typename std::iterator_traits<child_iterator>::reference;
33 using pointer = typename std::iterator_traits<child_iterator>::pointer;
34
35public:
36 constexpr recursive_iterator() noexcept = default;
37 constexpr recursive_iterator(recursive_iterator const& other) noexcept = default;
38 constexpr recursive_iterator(recursive_iterator&& other) noexcept = default;
39 constexpr recursive_iterator& operator=(recursive_iterator const& other) noexcept = default;
40 constexpr recursive_iterator& operator=(recursive_iterator&& other) noexcept = default;
41 ~recursive_iterator() = default;
42
45 constexpr recursive_iterator(parent_iterator parent_it, parent_iterator parent_it_end, child_iterator child_it) noexcept :
46 _parent_it(parent_it), _parent_it_end(parent_it_end), _child_it(child_it)
47 {
48 }
49
52 constexpr recursive_iterator(parent_iterator parent_it, parent_iterator parent_it_end) noexcept :
53 _parent_it(parent_it),
54 _parent_it_end(parent_it_end),
55 _child_it(parent_it != parent_it_end ? std::begin(*parent_it) : child_iterator{})
56 {
57 }
58
61 constexpr recursive_iterator(parent_iterator parent_it_end) noexcept :
62 _parent_it(parent_it_end), _parent_it_end(parent_it_end), _child_it()
63 {
64 }
65
68 [[nodiscard]] constexpr parent_iterator parent() const noexcept
69 {
70 return _parent_it;
71 }
72
76 [[nodiscard]] constexpr child_iterator child() const noexcept
77 {
78 hi_axiom(!at_end());
79 return _child_it;
80 }
81
89 [[nodiscard]] constexpr bool at_end() const noexcept
90 {
91 return _parent_it == _parent_it_end;
92 }
93
94 [[nodiscard]] constexpr reference operator*() const noexcept
95 {
96 return *_child_it;
97 }
98
99 [[nodiscard]] constexpr pointer operator->() const noexcept
100 {
101 return &(*_child_it);
102 }
103
104 [[nodiscard]] constexpr reference operator[](std::size_t i) const noexcept
105 {
106 return *(*this + i);
107 }
108
109 constexpr recursive_iterator& operator++() noexcept
110 {
111 ++_child_it;
112 if (_child_it == std::end(*_parent_it)) {
113 ++_parent_it;
114 if (!at_end()) {
115 _child_it = _parent_it->begin();
116 }
117 }
118 return *this;
119 }
120
121 constexpr recursive_iterator& operator--() noexcept
122 {
123 if (_child_it == std::begin(*_parent_it)) {
124 --_parent_it;
125 _child_it = std::end(*_parent_it);
126 }
127 --_child_it;
128 return *this;
129 }
130
131 constexpr recursive_iterator operator++(int) noexcept
132 {
133 auto tmp = *this;
134 ++(*this);
135 return tmp;
136 }
137
138 constexpr recursive_iterator operator--(int) noexcept
139 {
140 auto tmp = *this;
141 --(*this);
142 return tmp;
143 }
144
145 constexpr recursive_iterator& operator+=(difference_type rhs) noexcept
146 {
147 if (rhs < 0) {
148 return (*this) -= -rhs;
149 }
150
151 do {
152 auto const left_in_child = std::distance(_child_it, std::end(*_parent_it));
153
154 if (left_in_child <= rhs) {
155 ++_parent_it;
156 if (!at_end()) {
157 _child_it = std::begin(*_parent_it);
158 }
159 rhs -= left_in_child;
160
161 } else {
162 _child_it += rhs;
163 rhs -= rhs;
164 }
165
166 } while (rhs);
167
168 return *this;
169 }
170
171 constexpr recursive_iterator& operator-=(difference_type rhs) noexcept
172 {
173 if (rhs < 0) {
174 return (*this) += -rhs;
175 }
176
177 do {
178 auto const left_in_child = !at_end() ? std::distance(std::begin(*_parent_it), _child_it) + 1 : 0;
179
180 if (left_in_child < rhs) {
181 --_parent_it;
182 _child_it = std::end(*_parent_it) - 1;
183 rhs -= (left_in_child + 1);
184
185 } else {
186 _child_it -= rhs;
187 rhs -= rhs;
188 }
189
190 } while (rhs);
191
192 return *this;
193 }
194
195 [[nodiscard]] constexpr friend bool operator==(recursive_iterator const& lhs, recursive_iterator const& rhs) noexcept
196 {
197 if (lhs._parent_it != rhs._parent_it) {
198 return false;
199 } else if (lhs.at_end()) {
200 hi_axiom(rhs.at_end());
201 return true;
202 } else {
203 return lhs._child_it == rhs._child_it;
204 }
205 }
206
207 [[nodiscard]] constexpr friend std::strong_ordering
208 operator<=>(recursive_iterator const& lhs, recursive_iterator const& rhs) noexcept
209 {
210 if (lhs._parent_it != rhs._parent_it) {
211 return (lhs._parent_it - rhs._parent_it) <=> 0;
212 } else if (lhs.at_end()) {
213 hi_axiom(rhs.at_end());
214 return std::strong_ordering::equal;
215 } else {
216 return (lhs._child_it - rhs._child_it) <=> 0;
217 }
218 }
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-(recursive_iterator lhs, difference_type rhs) noexcept
225 {
226 return lhs -= rhs;
227 }
228 [[nodiscard]] constexpr friend recursive_iterator operator+(difference_type lhs, recursive_iterator rhs) noexcept
229 {
230 return rhs += lhs;
231 }
232
233 [[nodiscard]] constexpr friend difference_type
234 operator-(recursive_iterator const& lhs, recursive_iterator const& rhs) noexcept
235 {
236 if (rhs < lhs) {
237 return -(rhs - lhs);
238 } else {
239 auto lhs_ = lhs;
240 difference_type count = 0;
241 while (lhs_._parent_it < rhs._parent_it) {
242 count += std::distance(lhs_.child_it, std::end(*lhs_._parent_it));
243 ++(lhs_._parent_it);
244 lhs_._child_it = begin(*lhs_._parent_it);
245 }
246 return count + std::distance(lhs_._child_it, rhs._child_it);
247 }
248 }
249
250private:
251 parent_iterator _parent_it;
252 parent_iterator _parent_it_end;
253 child_iterator _child_it;
254};
255
258template<typename Container>
259[[nodiscard]] constexpr auto recursive_iterator_begin(Container& rhs) noexcept
260{
261 return recursive_iterator(begin(rhs), end(rhs));
262}
263
266template<typename Container>
267[[nodiscard]] constexpr auto recursive_iterator_end(Container& rhs) noexcept
268{
269 return recursive_iterator(end(rhs), end(rhs));
270}
271
274template<typename Container>
275[[nodiscard]] constexpr auto recursive_iterator_begin(Container const& rhs) noexcept
276{
277 return recursive_iterator(begin(rhs), end(rhs));
278}
279
282template<typename Container>
283[[nodiscard]] constexpr auto recursive_iterator_end(Container const& rhs) noexcept
284{
285 return recursive_iterator(end(rhs), end(rhs));
286}
287
288}} // 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.
The HikoGUI namespace.
Definition array_generic.hpp:20
constexpr auto recursive_iterator_begin(Container &rhs) noexcept
Get a recursive iterator from the begin of a recursive container.
Definition recursive_iterator.hpp:259
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:267
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
An iterator which recursively iterates through nested containers.
Definition recursive_iterator.hpp:23
constexpr child_iterator child() const noexcept
Get the current child iterator.
Definition recursive_iterator.hpp:76
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:45
constexpr bool at_end() const noexcept
Check if the iterator is at end.
Definition recursive_iterator.hpp:89
constexpr recursive_iterator(parent_iterator parent_it_end) noexcept
Create an end iterator one beyond the last child.
Definition recursive_iterator.hpp:61
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:52
constexpr parent_iterator parent() const noexcept
Get the current parent iterator.
Definition recursive_iterator.hpp:68
T begin(T... args)
T count(T... args)
T distance(T... args)
T end(T... args)