source: mainline/uspace/lib/cpp/include/internal/rbtree_iterators.hpp@ 47203ee3

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

cpp: fixed conversions from non-const iterators to const iterators

  • Property mode set to 100644
File size: 13.5 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/iterator.hpp>
33#include <internal/rbtree_node.hpp>
34#include <iterator>
35
36namespace std::aux
37{
38 /**
39 * Note: In order for these iterators to be reversible,
40 * the end state of an iterator is represented by a flag
41 * which can be set from true to false in operator--
42 * (i.e. decrementing end iterator) or set from false to
43 * true in operator++ (i.e. incrementing last before end
44 * iterator).
45 */
46
47 template<class Value, class Reference, class Pointer, class Size>
48 class rbtree_iterator
49 {
50 public:
51 using value_type = Value;
52 using size_type = Size;
53 using reference = Reference;
54 using pointer = Pointer;
55 using difference_type = ptrdiff_t;
56
57 using iterator_category = bidirectional_iterator_tag;
58
59 rbtree_iterator(rbtree_node<value_type>* current = nullptr, bool end = true)
60 : current_{current}, end_{end}
61 { /* DUMMY BODY */ }
62
63 rbtree_iterator(const rbtree_iterator&) = default;
64 rbtree_iterator& operator=(const rbtree_iterator&) = default;
65
66 reference operator*() const
67 {
68 return current_->value;
69 }
70
71 pointer operator->() const
72 {
73 return &current_->value;
74 }
75
76 rbtree_iterator& operator++()
77 {
78 if (current_)
79 {
80 auto bckp = current_;
81 if (current_->right)
82 current_ = current_->right->find_smallest();
83 else
84 {
85 while (!current_->is_left_child())
86 {
87 current_ = current_->parent;
88
89 if (!current_ || !current_->parent)
90 {
91 /**
92 * We've gone back to root without
93 * being a left child, which means we
94 * were the last node.
95 */
96 end_ = true;
97 current_ = bckp;
98
99 return *this;
100 }
101 }
102
103 /**
104 * Now we are a left child,
105 * so the next node we have to visit
106 * is our parent.
107 */
108 current_ = current_->parent;
109 }
110 }
111
112 return *this;
113 }
114
115 rbtree_iterator operator++(int)
116 {
117 auto tmp = *this;
118 ++(*this);
119
120 return tmp;
121 }
122
123 rbtree_iterator& operator--()
124 {
125 if (end_)
126 {
127 try_undo_end_();
128
129 return *this;
130 }
131
132 if (current_)
133 {
134 if (current_->left)
135 current_ = current_->left->find_largest();
136 else if (current_->parent)
137 {
138 while (current_->is_left_child())
139 current_ = current_->parent;
140
141 /**
142 * We know parent exists here
143 * because we went up from the
144 * left and stopped being left
145 * child (if at any point we happened
146 * to become root then this branch
147 * wouldn't happen).
148 */
149 current_ = current_->parent;
150 }
151 else // We are root without a left child.
152 end_ = true;
153 }
154
155 return *this;
156 }
157
158 rbtree_iterator operator--(int)
159 {
160 auto tmp = *this;
161 --(*this);
162
163 return tmp;
164 }
165
166 const rbtree_node<value_type>* node() const
167 {
168 return current_;
169 }
170
171 rbtree_node<value_type>* node()
172 {
173 return current_;
174 }
175
176 bool end() const
177 {
178 return end_;
179 }
180
181 private:
182 rbtree_node<value_type>* current_;
183 bool end_;
184
185 void try_undo_end_()
186 {
187 if (!current_)
188 return;
189
190 /**
191 * We can do this if we are past end().
192 * This means we are the largest.
193 */
194 if (current_->find_largest() == current_)
195 end_ = false;
196 }
197 };
198
199 template<class Val, class Ref, class Ptr, class Sz>
200 bool operator==(const rbtree_iterator<Val, Ref, Ptr, Sz>& lhs,
201 const rbtree_iterator<Val, Ref, Ptr, Sz>& rhs)
202 {
203 return (lhs.node() == rhs.node()) && (lhs.end() == rhs.end());
204 }
205
206 template<class Val, class Ref, class Ptr, class Sz>
207 bool operator!=(const rbtree_iterator<Val, Ref, Ptr, Sz>& lhs,
208 const rbtree_iterator<Val, Ref, Ptr, Sz>& rhs)
209 {
210 return !(lhs == rhs);
211 }
212
213 template<class Value, class ConstReference, class ConstPointer, class Size>
214 class rbtree_const_iterator
215 {
216 using non_const_iterator_type = rbtree_iterator<
217 Value, get_non_const_ref_t<ConstReference>,
218 get_non_const_ptr_t<ConstPointer>, Size
219 >;
220
221 public:
222 using value_type = Value;
223 using size_type = Size;
224 using const_reference = ConstReference;
225 using const_pointer = ConstPointer;
226 using difference_type = ptrdiff_t;
227
228 using iterator_category = bidirectional_iterator_tag;
229
230 rbtree_const_iterator(const rbtree_node<value_type>* current = nullptr, bool end = true)
231 : current_{current}, end_{end}
232 { /* DUMMY BODY */ }
233
234 rbtree_const_iterator(const rbtree_const_iterator&) = default;
235 rbtree_const_iterator& operator=(const rbtree_const_iterator&) = default;
236
237 rbtree_const_iterator(const non_const_iterator_type& other)
238 : current_{other.node()}, end_{other.end()}
239 { /* DUMMY BODY */ }
240
241 rbtree_const_iterator& operator=(const non_const_iterator_type& other)
242 {
243 current_ = other.node();
244 end_ = other.end();
245
246 return *this;
247 }
248
249 const_reference operator*() const
250 {
251 return current_->value;
252 }
253
254 const_pointer operator->() const
255 {
256 return &current_->value;
257 }
258
259 rbtree_const_iterator& operator++()
260 {
261 if (current_)
262 {
263 auto bckp = current_;
264 if (current_->right)
265 current_ = current_->right->find_smallest();
266 else
267 {
268 while (!current_->is_left_child())
269 {
270 current_ = current_->parent;
271
272 if (!current_->parent)
273 {
274 /**
275 * We've gone back to root without
276 * being a left child, which means we
277 * were the last node.
278 */
279 end_ = true;
280 current_ = bckp;
281
282 return *this;
283 }
284 }
285
286 /**
287 * Now we are a left child,
288 * so the next node we have to visit
289 * is our parent.
290 */
291 current_ = current_->parent;
292 }
293 }
294
295 return *this;
296 }
297
298 rbtree_const_iterator operator++(int)
299 {
300 auto tmp = *this;
301 ++(*this);
302
303 return tmp;
304 }
305
306 rbtree_const_iterator& operator--()
307 {
308 if (end_)
309 {
310 try_undo_end_();
311
312 return *this;
313 }
314
315 if (current_)
316 {
317 if (current_->left)
318 current_ = current_->left->find_largest();
319 else if (current_->parent)
320 {
321 while (current_->is_left_child())
322 current_ = current_->parent;
323
324 /**
325 * We know parent exists here
326 * because we went up from the
327 * left and stopped being left
328 * child (if at any point we happened
329 * to become root then this branch
330 * wouldn't happen).
331 */
332 current_ = current_->parent;
333 }
334 else // We are root without a left child.
335 current_ = nullptr;
336 }
337
338 return *this;
339 }
340
341 rbtree_const_iterator operator--(int)
342 {
343 auto tmp = *this;
344 --(*this);
345
346 return tmp;
347 }
348
349 const rbtree_node<value_type>* node() const
350 {
351 return current_;
352 }
353
354 bool end() const
355 {
356 return end_;
357 }
358
359 private:
360 const rbtree_node<value_type>* current_;
361 bool end_;
362
363 void try_undo_end_()
364 {
365 if (!current_)
366 return;
367
368 /**
369 * We can do this if we are past end().
370 * This means we are the largest.
371 */
372 if (current_->find_largest() == current_)
373 end_ = false;
374 }
375 };
376
377 template<class Val, class CRef, class CPtr, class Sz>
378 bool operator==(const rbtree_const_iterator<Val, CRef, CPtr, Sz>& lhs,
379 const rbtree_const_iterator<Val, CRef, CPtr, Sz>& rhs)
380 {
381 return (lhs.node() == rhs.node()) && (lhs.end() == rhs.end());
382 }
383
384 template<class Val, class CRef, class CPtr, class Sz>
385 bool operator!=(const rbtree_const_iterator<Val, CRef, CPtr, Sz>& lhs,
386 const rbtree_const_iterator<Val, CRef, CPtr, Sz>& rhs)
387 {
388 return !(lhs == rhs);
389 }
390
391 template<class Val, class Ref, class Ptr, class CRef, class CPtr, class Sz>
392 bool operator==(const rbtree_iterator<Val, Ref, Ptr, Sz>& lhs,
393 const rbtree_const_iterator<Val, CRef, CPtr, Sz>& rhs)
394 {
395 return (lhs.node() == rhs.node()) && (lhs.end() == rhs.end());
396 }
397
398 template<class Val, class Ref, class Ptr, class CRef, class CPtr, class Sz>
399 bool operator!=(const rbtree_iterator<Val, Ref, Ptr, Sz>& lhs,
400 const rbtree_const_iterator<Val, CRef, CPtr, Sz>& rhs)
401 {
402 return !(lhs == rhs);
403 }
404
405 template<class Val, class CRef, class CPtr, class Ref, class Ptr, class Sz>
406 bool operator==(const rbtree_const_iterator<Val, CRef, CPtr, Sz>& lhs,
407 const rbtree_iterator<Val, Ref, Ptr, Sz>& rhs)
408 {
409 return (lhs.node() == rhs.node()) && (lhs.end() == rhs.end());
410 }
411
412 template<class Val, class CRef, class CPtr, class Ref, class Ptr, class Sz>
413 bool operator!=(const rbtree_const_iterator<Val, CRef, CPtr, Sz>& lhs,
414 const rbtree_iterator<Val, Ref, Ptr, Sz>& rhs)
415 {
416 return !(lhs == rhs);
417 }
418}
419
420#endif
Note: See TracBrowser for help on using the repository browser.