source: mainline/uspace/lib/cpp/include/internal/rbtree_iterators.hpp@ 009d78b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 009d78b was 4d65515, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: added a WIP version of a generic red black tree, well, currently a BST

  • Property mode set to 100644
File size: 11.8 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_INTERNAL_RBTREE_ITERATORS
30#define LIBCPP_INTERNAL_RBTREE_ITERATORS
31
32#include <internal/rbtree_node.hpp>
33#include <iterator>
34
35namespace std::aux
36{
37 /**
38 * Note: In order for these iterators to be reversible,
39 * the end state of an iterator is represented by a flag
40 * which can be set from true to false in operator--
41 * (i.e. decrementing end iterator) or set from false to
42 * true in operator++ (i.e. incrementing last before end
43 * iterator).
44 */
45
46 template<class Value, class ConstReference, class ConstPointer, class Size>
47 class rbtree_const_iterator
48 {
49 public:
50 using value_type = Value;
51 using size_type = Size;
52 using const_reference = ConstReference;
53 using const_pointer = ConstPointer;
54 using difference_type = ptrdiff_t;
55
56 using iterator_category = bidirectional_iterator_tag;
57
58 rbtree_const_iterator(const rbtree_node<value_type>* current = nullptr, bool end = true)
59 : current_{current}, end_{end}
60 { /* DUMMY BODY */ }
61
62 rbtree_const_iterator(const rbtree_const_iterator&) = default;
63 rbtree_const_iterator& operator=(const rbtree_const_iterator&) = default;
64
65 const_reference operator*() const
66 {
67 return current_->value;
68 }
69
70 const_pointer operator->() const
71 {
72 return &current_->value;
73 }
74
75 rbtree_const_iterator& operator++()
76 {
77 if (current_)
78 {
79 auto bckp = current_;
80 if (current_->right)
81 current_ = current_->right->find_smallest();
82 else
83 {
84 while (!current_->is_left_child())
85 {
86 current_ = current_->parent;
87
88 if (!current_->parent)
89 {
90 /**
91 * We've gone back to root without
92 * being a left child, which means we
93 * were the last node.
94 */
95 end_ = true;
96 current_ = bckp;
97
98 return *this;
99 }
100 }
101
102 /**
103 * Now we are a left child,
104 * so the next node we have to visit
105 * is our parent.
106 */
107 current_ = current_->parent;
108 }
109 }
110
111 return *this;
112 }
113
114 rbtree_const_iterator operator++(int)
115 {
116 auto tmp = *this;
117 ++(*this);
118
119 return tmp;
120 }
121
122 rbtree_const_iterator& operator--()
123 {
124 if (end_)
125 {
126 try_undo_end_();
127
128 return *this;
129 }
130
131 if (current_)
132 {
133 if (current_->left)
134 current_ = current_->left->find_largest();
135 else if (current_->parent)
136 {
137 while (current_->is_left_child())
138 current_ = current_->parent;
139
140 /**
141 * We know parent exists here
142 * because we went up from the
143 * left and stopped being left
144 * child (if at any point we happened
145 * to become root then this branch
146 * wouldn't happen).
147 */
148 current_ = current_->parent;
149 }
150 else // We are root without a left child.
151 current_ = nullptr;
152 }
153
154 return *this;
155 }
156
157 rbtree_const_iterator operator--(int)
158 {
159 auto tmp = *this;
160 --(*this);
161
162 return tmp;
163 }
164
165 const rbtree_node<value_type>* node() const
166 {
167 return current_;
168 }
169
170 bool end() const
171 {
172 return end_;
173 }
174
175 private:
176 const rbtree_node<value_type>* current_;
177 bool end_;
178
179 void try_undo_end_()
180 {
181 if (!current_)
182 return;
183
184 /**
185 * We can do this if we are past end().
186 * This means we are the largest.
187 */
188 if (current_->find_largest() == current_)
189 end_ = false;
190 }
191 };
192
193 template<class Val, class CRef, class CPtr, class Sz>
194 bool operator==(const rbtree_const_iterator<Val, CRef, CPtr, Sz>& lhs,
195 const rbtree_const_iterator<Val, CRef, CPtr, Sz>& rhs)
196 {
197 return (lhs.node() == rhs.node()) && (lhs.end() == rhs.end());
198 }
199
200 template<class Val, class CRef, class CPtr, class Sz>
201 bool operator!=(const rbtree_const_iterator<Val, CRef, CPtr, Sz>& lhs,
202 const rbtree_const_iterator<Val, CRef, CPtr, Sz>& rhs)
203 {
204 return !(lhs == rhs);
205 }
206
207 template<class Value, class Reference, class Pointer, class Size>
208 class rbtree_iterator
209 {
210 public:
211 using value_type = Value;
212 using size_type = Size;
213 using reference = Reference;
214 using pointer = Pointer;
215 using difference_type = ptrdiff_t;
216
217 using iterator_category = bidirectional_iterator_tag;
218
219 rbtree_iterator(rbtree_node<value_type>* current = nullptr, bool end = true)
220 : current_{current}, end_{end}
221 { /* DUMMY BODY */ }
222
223 rbtree_iterator(const rbtree_iterator&) = default;
224 rbtree_iterator& operator=(const rbtree_iterator&) = default;
225
226 reference operator*() const
227 {
228 return current_->value;
229 }
230
231 pointer operator->() const
232 {
233 return &current_->value;
234 }
235
236 rbtree_iterator& operator++()
237 {
238 if (current_)
239 {
240 auto bckp = current_;
241 if (current_->right)
242 current_ = current_->right->find_smallest();
243 else
244 {
245 while (!current_->is_left_child())
246 {
247 current_ = current_->parent;
248
249 if (!current_ || !current_->parent)
250 {
251 /**
252 * We've gone back to root without
253 * being a left child, which means we
254 * were the last node.
255 */
256 end_ = true;
257 current_ = bckp;
258
259 return *this;
260 }
261 }
262
263 /**
264 * Now we are a left child,
265 * so the next node we have to visit
266 * is our parent.
267 */
268 current_ = current_->parent;
269 }
270 }
271
272 return *this;
273 }
274
275 rbtree_iterator operator++(int)
276 {
277 auto tmp = *this;
278 ++(*this);
279
280 return tmp;
281 }
282
283 rbtree_iterator& operator--()
284 {
285 if (end_)
286 {
287 try_undo_end_();
288
289 return *this;
290 }
291
292 if (current_)
293 {
294 if (current_->left)
295 current_ = current_->left->find_largest();
296 else if (current_->parent)
297 {
298 while (current_->is_left_child())
299 current_ = current_->parent;
300
301 /**
302 * We know parent exists here
303 * because we went up from the
304 * left and stopped being left
305 * child (if at any point we happened
306 * to become root then this branch
307 * wouldn't happen).
308 */
309 current_ = current_->parent;
310 }
311 else // We are root without a left child.
312 end_ = true;
313 }
314
315 return *this;
316 }
317
318 rbtree_iterator operator--(int)
319 {
320 auto tmp = *this;
321 --(*this);
322
323 return tmp;
324 }
325
326 const rbtree_node<value_type>* node() const
327 {
328 return current_;
329 }
330
331 rbtree_node<value_type>* node()
332 {
333 return current_;
334 }
335
336 bool end() const
337 {
338 return end_;
339 }
340
341 private:
342 rbtree_node<value_type>* current_;
343 bool end_;
344
345 void try_undo_end_()
346 {
347 if (!current_)
348 return;
349
350 /**
351 * We can do this if we are past end().
352 * This means we are the largest.
353 */
354 if (current_->find_largest() == current_)
355 end_ = false;
356 }
357 };
358
359 template<class Val, class Ref, class Ptr, class Sz>
360 bool operator==(const rbtree_iterator<Val, Ref, Ptr, Sz>& lhs,
361 const rbtree_iterator<Val, Ref, Ptr, Sz>& rhs)
362 {
363 return (lhs.node() == rhs.node()) && (lhs.end() == rhs.end());
364 }
365
366 template<class Val, class Ref, class Ptr, class Sz>
367 bool operator!=(const rbtree_iterator<Val, Ref, Ptr, Sz>& lhs,
368 const rbtree_iterator<Val, Ref, Ptr, Sz>& rhs)
369 {
370 return !(lhs == rhs);
371 }
372}
373
374#endif
Note: See TracBrowser for help on using the repository browser.