stlab 2.3.0
Modern, modular C++ algorithms, data structures, and concurrency primitives
Loading...
Searching...
No Matches
forest.hpp
Go to the documentation of this file.
1/*
2 Copyright 2013 Adobe
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5*/
6/**************************************************************************************************/
7
8#ifndef STLAB_FOREST_HPP
9#define STLAB_FOREST_HPP
10
26
27/**************************************************************************************************/
28
29#include <array>
30#include <atomic>
31#include <cassert>
32#include <cstddef>
33#include <cstdint>
34#include <iterator>
35#include <utility>
36
38#include <stlab/config.hpp>
40
41/**************************************************************************************************/
42
43namespace stlab {
44STLAB_VERSION_NAMESPACE_BEGIN()
45
46
56
57/**************************************************************************************************/
58
59
60enum class forest_edge : bool { trailing, leading };
61
62constexpr auto forest_trailing_edge{forest_edge::trailing};
63constexpr auto forest_leading_edge{forest_edge::leading};
64
65/**************************************************************************************************/
66
68constexpr auto pivot(forest_edge e) { return forest_edge(static_cast<bool>(e) ^ 1); }
69
71template <class I> // I models FullorderIterator
72void pivot(I& i) {
73 i.edge() = pivot(i.edge());
74}
75
77template <class I> // I models FullorderIterator
78auto pivot_of(I i) {
79 pivot(i);
80 return i;
81}
82
83/**************************************************************************************************/
84
86template <class I> // I models a FullorderIterator
87auto leading_of(I i) {
88 i.edge() = forest_edge::leading;
89 return i;
90}
91
93template <class I> // I models a FullorderIterator
94auto trailing_of(I i) {
95 i.edge() = forest_edge::trailing;
96 return i;
97}
98
99/**************************************************************************************************/
100
102constexpr auto is_leading(forest_edge e) { return e == forest_edge::leading; }
103
105template <class I> // I models a FullorderIterator
106auto is_leading(const I& i) {
107 return is_leading(i.edge());
108}
109
111constexpr auto is_trailing(forest_edge e) { return e == forest_edge::trailing; }
112
114template <class I> // I models a FullorderIterator
115auto is_trailing(const I& i) {
116 return is_trailing(i.edge());
117}
118
119/**************************************************************************************************/
120
129template <class I> // I models FullorderIterator
130auto find_parent(I i) -> I {
131 do {
132 i = std::next(trailing_of(i));
133 } while (i.edge() != forest_edge::trailing);
134 return i;
135}
136
137/**************************************************************************************************/
138
139template <class I> // I models FullorderIterator
140auto has_children(const I& i) -> bool {
141 return !i.equal_node(std::next(leading_of(i)));
142}
143
144/**************************************************************************************************/
145
148template <class I> // I models FullorderIterator
149struct child_iterator {
150 using value_type = typename std::iterator_traits<I>::value_type;
151 using difference_type = typename std::iterator_traits<I>::difference_type;
152 using reference = typename std::iterator_traits<I>::reference;
153 using pointer = typename std::iterator_traits<I>::pointer;
154 using iterator_category = typename std::iterator_traits<I>::iterator_category;
155
156 child_iterator() = default;
157 explicit child_iterator(const I& x) : _x(std::move(x)) {}
158 template <class U>
159 child_iterator(const child_iterator<U>& u) : _x(u.base()) {}
160
161 [[nodiscard]] auto base() const -> I { return _x; }
162
163 auto operator*() -> reference { return dereference(); }
164 auto operator->() -> pointer { return &dereference(); }
165 auto operator++() -> auto& {
166 increment();
167 return *this;
168 }
169 auto operator++(int) -> child_iterator {
170 auto result{*this};
171 increment();
172 return result;
173 }
174 auto operator--() -> auto& {
175 decrement();
176 return *this;
177 }
178 auto operator--(int) -> child_iterator {
179 auto result{*this};
180 decrement();
181 return result;
182 }
183
184 friend auto operator==(const child_iterator& a, const child_iterator& b) -> bool {
185 return a.base() == b.base();
186 }
187 friend auto operator!=(const child_iterator& a, const child_iterator& b) -> bool {
188 return !(a == b);
189 }
190
191private:
192 I _x;
193
194 void increment() {
195 pivot(_x);
196 ++_x;
197 }
198 void decrement() {
199 --_x;
200 pivot(_x);
201 }
202
203 auto dereference() -> reference { return *_x; }
204};
205
206/**************************************************************************************************/
207
209template <class I> // I models FullorderIterator
210auto find_edge(I x, forest_edge edge) -> I {
211 while (x.edge() != edge)
212 ++x;
213 return x;
214}
215
217template <class I> // I models FullorderIterator
218auto find_edge_reverse(I x, forest_edge edge) -> I {
219 while (x.edge() != edge)
220 --x;
221 return x;
222}
223
224/**************************************************************************************************/
225
228template <class I, forest_edge Edge> // I models FullorderIterator
229struct edge_iterator {
230 using value_type = typename std::iterator_traits<I>::value_type;
231 using difference_type = typename std::iterator_traits<I>::difference_type;
232 using reference = typename std::iterator_traits<I>::reference;
233 using pointer = typename std::iterator_traits<I>::pointer;
234 using iterator_category = typename std::iterator_traits<I>::iterator_category;
235
236 edge_iterator() = default;
237 explicit edge_iterator(const I& x) : _x(find_edge(x, Edge)) {}
238 template <class U>
239 edge_iterator(const edge_iterator<U, Edge>& u) : _x(u.base()) {}
240
241 [[nodiscard]] auto base() const -> I { return _x; }
242
243 auto operator*() -> reference { return dereference(); }
244 auto operator->() -> pointer { return &dereference(); }
245 auto operator++() -> auto& {
246 increment();
247 return *this;
248 }
249 auto operator++(int) -> edge_iterator {
250 auto result{*this};
251 increment();
252 return result;
253 }
254 auto operator--() -> auto& {
255 decrement();
256 return *this;
257 }
258 auto operator--(int) -> edge_iterator {
259 auto result{*this};
260 decrement();
261 return result;
262 }
263
264 friend auto operator==(const edge_iterator& a, const edge_iterator& b) -> bool {
265 return a.base() == b.base();
266 }
267 friend auto operator!=(const edge_iterator& a, const edge_iterator& b) -> bool {
268 return !(a == b);
269 }
270
271private:
272 I _x;
273
274 void increment() { _x = find_edge(std::next(_x), Edge); }
275
276 void decrement() { _x = find_edge_reverse(std::prev(_x), Edge); }
277
278 auto dereference() -> reference { return *_x; }
279};
280
281/**************************************************************************************************/
282
285template <class I, // I models a Forest
286 class P> // P models UnaryPredicate of value_type(I)
287struct filter_fullorder_iterator {
288 using value_type = typename std::iterator_traits<I>::value_type;
289 using difference_type = typename std::iterator_traits<I>::difference_type;
290 using reference = typename std::iterator_traits<I>::reference;
291 using pointer = typename std::iterator_traits<I>::pointer;
292 using iterator_category = typename std::iterator_traits<I>::iterator_category;
293
294 filter_fullorder_iterator() = default;
295
296 filter_fullorder_iterator(I f, I l, P p) :
297 _x(skip_forward(f, l, p)), _inside(true), _first(f), _last(l), _predicate(p) {}
298
299 filter_fullorder_iterator(I f, I l) :
300 _x(skip_forward(f, l, P())), _inside(true), _first(f), _last(l) {}
301
302 template <class U>
303 filter_fullorder_iterator(const filter_fullorder_iterator<U, P>& x) :
304 _x(x.base()), _inside(x._inside), _first(x._first), _last(x._last),
305 _predicate(x._predicate) {}
306
307 auto predicate() const -> P { return _predicate; }
308
309 [[nodiscard]] auto edge() const -> forest_edge { return this->base().edge(); }
310 auto edge() -> forest_edge& { return this->base_reference().edge(); }
311
312 auto equal_node(const filter_fullorder_iterator& y) const -> bool {
313 return this->base().equal_node(y.base());
314 }
315
316 auto base() const -> I { return _x; }
317 auto base_reference() -> I& { return _x; }
318
319 auto operator*() -> reference { return dereference(); }
320 auto operator->() -> pointer { return &dereference(); }
321 auto operator++() -> auto& {
322 increment();
323 return *this;
324 }
325 auto operator++(int) -> filter_fullorder_iterator {
326 auto result{*this};
327 increment();
328 return result;
329 }
330 auto operator--() -> auto& {
331 decrement();
332 return *this;
333 }
334 auto operator--(int) -> filter_fullorder_iterator {
335 auto result{*this};
336 decrement();
337 return result;
338 }
339
340 friend auto operator==(const filter_fullorder_iterator& a, const filter_fullorder_iterator& b)
341 -> bool {
342 return a.base() == b.base();
343 }
344 friend auto operator!=(const filter_fullorder_iterator& a, const filter_fullorder_iterator& b)
345 -> bool {
346 return !(a == b);
347 }
348
349private:
350 I _x;
351 bool _inside;
352 I _first;
353 I _last;
354 P _predicate;
355
356 void increment() {
357 I i = this->base();
358
359 if (i == _last) _inside = false;
360 ++i;
361 if (i == _first) _inside = true;
362 if (_inside) i = skip_forward(i, _last, _predicate);
363 this->base_reference() = i;
364 }
365
366 static auto skip_forward(I f, I l, P p) -> I
367 // Precondition: l is on a leading edge
368 {
369 while ((f.edge() == forest_edge::leading) && (f != l) && !p(*f)) {
370 f.edge() = forest_edge::trailing;
371 ++f;
372 }
373 return f;
374 }
375
376 static auto skip_backward(I f, I l, P p) -> I
377 // Precondition: f is on a trailing edge
378 {
379 while ((l.edge() == forest_edge::trailing) && (f != l) && !p(*l)) {
380 l.edge() = forest_edge::leading;
381 --l;
382 }
383 return l;
384 }
385
386 void decrement() {
387 I i = this->base();
388
389 if (i == _first) _inside = false;
390 --i;
391 if (i == _last) _inside = true;
392 if (_inside) i = skip_backward(_first, i, _predicate);
393 this->base_reference() = i;
394 }
395
396 auto dereference() -> reference { return *_x; }
397};
398
399/**************************************************************************************************/
400
402template <class I> // I models a FullorderIterator
403struct reverse_fullorder_iterator {
404 using iterator_type = I;
405
406 using value_type = typename std::iterator_traits<I>::value_type;
407 using difference_type = typename std::iterator_traits<I>::difference_type;
408 using reference = typename std::iterator_traits<I>::reference;
409 using pointer = typename std::iterator_traits<I>::pointer;
410 using iterator_category = typename std::iterator_traits<I>::iterator_category;
411
412 reverse_fullorder_iterator() : _edge(forest_edge::trailing) {}
413 explicit reverse_fullorder_iterator(I x) : _base(--x), _edge(pivot(_base.edge())) {}
414 template <class U>
415 reverse_fullorder_iterator(const reverse_fullorder_iterator<U>& x) :
416 _base(--x.base()), _edge(pivot(_base.edge())) {}
417
418 [[nodiscard]] auto base() const -> iterator_type { return std::next(_base); }
419
420 [[nodiscard]] auto edge() const -> forest_edge { return _edge; }
421 auto edge() -> forest_edge& { return _edge; }
422
423 [[nodiscard]] auto equal_node(const reverse_fullorder_iterator& y) const -> bool {
424 return _base.equal_node(y._base);
425 }
426
427 auto operator*() -> reference { return dereference(); }
428 auto operator->() -> pointer { return &dereference(); }
429 auto operator++() -> auto& {
430 increment();
431 return *this;
432 }
433 auto operator++(int) -> reverse_fullorder_iterator {
434 auto result{*this};
435 increment();
436 return result;
437 }
438 auto operator--() -> auto& {
439 decrement();
440 return *this;
441 }
442 auto operator--(int) -> reverse_fullorder_iterator {
443 auto result{*this};
444 decrement();
445 return result;
446 }
447
448 friend auto operator==(const reverse_fullorder_iterator& a, const reverse_fullorder_iterator& b)
449 -> bool {
450 return a.equal(b);
451 }
452 friend auto operator!=(const reverse_fullorder_iterator& a, const reverse_fullorder_iterator& b)
453 -> bool {
454 return !(a == b);
455 }
456
457private:
458 I _base;
459 forest_edge _edge;
460
461 void increment() {
462 _base.edge() = pivot(_edge);
463 --_base;
464 _edge = pivot(_base.edge());
465 }
466 void decrement() {
467 _base.edge() = pivot(_edge);
468 ++_base;
469 _edge = pivot(_base.edge());
470 }
471 [[nodiscard]] auto dereference() const -> reference { return *_base; }
472
473 [[nodiscard]] auto equal(const reverse_fullorder_iterator& y) const -> bool {
474 return (_base == y._base) && (_edge == y._edge);
475 }
476};
477
478/**************************************************************************************************/
479
481template <class I> // I models FullorderIterator
482struct depth_fullorder_iterator {
483 using value_type = typename std::iterator_traits<I>::value_type;
484 using difference_type = typename std::iterator_traits<I>::difference_type;
485 using reference = typename std::iterator_traits<I>::reference;
486 using pointer = typename std::iterator_traits<I>::pointer;
487 using iterator_category = typename std::iterator_traits<I>::iterator_category;
488
489 depth_fullorder_iterator(difference_type d = 0) : _depth(d) {}
490 explicit depth_fullorder_iterator(I x, difference_type d = 0) : _x(x), _depth(d) {}
491 template <class U>
492 depth_fullorder_iterator(const depth_fullorder_iterator<U>& x) :
493 _x(x.base()), _depth(x._depth) {}
494
495 auto depth() const -> difference_type { return _depth; }
496 [[nodiscard]] auto edge() const -> forest_edge { return this->base().edge(); }
497 auto edge() -> forest_edge& { return _x.edge(); }
498 auto equal_node(depth_fullorder_iterator const& y) const -> bool {
499 return this->base().equal_node(y.base());
500 }
501
502 auto base() const -> I { return _x; }
503
504 auto operator*() -> reference { return dereference(); }
505 auto operator->() -> pointer { return &dereference(); }
506 auto operator++() -> auto& {
507 increment();
508 return *this;
509 }
510 auto operator++(int) -> depth_fullorder_iterator {
511 auto result{*this};
512 increment();
513 return result;
514 }
515 auto operator--() -> auto& {
516 decrement();
517 return *this;
518 }
519 auto operator--(int) -> depth_fullorder_iterator {
520 auto result{*this};
521 decrement();
522 return result;
523 }
524
525 friend auto operator==(const depth_fullorder_iterator& a, const depth_fullorder_iterator& b)
526 -> bool {
527 return a.base() == b.base();
528 }
529 friend auto operator!=(const depth_fullorder_iterator& a, const depth_fullorder_iterator& b)
530 -> bool {
531 return !(a == b);
532 }
533
534private:
535 I _x;
536 difference_type _depth;
537
538 void increment() {
539 forest_edge old_edge(edge());
540 ++_x;
541 if (old_edge == edge())
542 _depth += difference_type(static_cast<std::size_t>(old_edge) << 1) - 1;
543 }
544
545 void decrement() {
546 forest_edge old_edge(edge());
547 --_x;
548 if (old_edge == edge())
549 _depth -= difference_type(static_cast<std::size_t>(old_edge) << 1) - 1;
550 }
551
552 auto dereference() -> reference { return *_x; }
553};
554
555/**************************************************************************************************/
556
557template <class Forest>
558class child_adaptor;
559template <class T>
560class forest;
561
562/**************************************************************************************************/
563
564namespace detail {
565
566/**************************************************************************************************/
567
568template <class D> // derived class
569struct node_base {
570 enum next_prior_t : std::uint8_t { prior_s, next_s };
571
572 using node_ptr = D*;
573 using reference = node_ptr&;
574
575 auto link(forest_edge edge, next_prior_t link) -> node_ptr& {
576 return _nodes[static_cast<std::size_t>(edge)][static_cast<std::size_t>(link)];
577 }
578
579 [[nodiscard]] auto link(forest_edge edge, next_prior_t link) const -> node_ptr {
580 return _nodes[static_cast<std::size_t>(edge)][static_cast<std::size_t>(link)];
581 }
582
583 std::array<std::array<node_ptr, 2>, 2> _nodes{nullptr};
584
585 node_base() :
586 _nodes{std::array{static_cast<node_ptr>(this), static_cast<node_ptr>(this)},
587 std::array{static_cast<node_ptr>(this), static_cast<node_ptr>(this)}} {}
588};
589
590template <class T> // T models Regular
591struct node : public node_base<node<T>> {
592 using value_type = T;
593
594 explicit node(value_type data) : _data(std::move(data)) {}
595
596 value_type _data;
597};
598
599/**************************************************************************************************/
600
601template <class T>
602struct forest_const_iterator;
603
604template <class T> // T is value_type
605struct forest_iterator {
606 using value_type = T;
607 using difference_type = std::ptrdiff_t;
608 using reference = T&;
609 using pointer = T*;
610 using iterator_category = std::bidirectional_iterator_tag;
611
612 forest_iterator() = default;
613
614 forest_iterator(const forest_iterator& x) : _node(x._node), _edge(x._edge) {}
615
616 auto operator=(const forest_iterator&) -> forest_iterator& = default;
617
618 [[nodiscard]] auto edge() const -> forest_edge { return _edge; }
619 auto edge() -> forest_edge& { return _edge; }
620
621 [[nodiscard]] auto equal_node(forest_iterator const& y) const -> bool {
622 return _node == y._node;
623 }
624
625 auto operator*() const -> reference { return dereference(); }
626 auto operator->() const -> pointer { return &dereference(); }
627 auto operator++() -> auto& {
628 increment();
629 return *this;
630 }
631 auto operator++(int) -> forest_iterator {
632 auto result{*this};
633 increment();
634 return result;
635 }
636 auto operator--() -> auto& {
637 decrement();
638 return *this;
639 }
640 auto operator--(int) -> forest_iterator {
641 auto result{*this};
642 decrement();
643 return result;
644 }
645
646 friend auto operator==(const forest_iterator& a, const forest_iterator& b) -> bool {
647 return a.equal(b);
648 }
649 friend auto operator!=(const forest_iterator& a, const forest_iterator& b) -> bool {
650 return !(a == b);
651 }
652
653private:
654 friend class stlab::forest<value_type>;
655 template <class>
656 friend struct forest_iterator;
657 template <class>
658 friend struct forest_const_iterator;
659 friend struct unsafe::set_next_fn<forest_iterator>;
660
661 using node_t = node<T>;
662
663 [[nodiscard]] auto dereference() const -> reference { return _node->_data; }
664
665 void increment() {
666 node_t* next(_node->link(_edge, node_t::next_s));
667
668 if (is_leading(_edge))
669 _edge = forest_edge(next != _node);
670 else
671 _edge = forest_edge(next->link(forest_edge::leading, node_t::prior_s) == _node);
672
673 _node = next;
674 }
675
676 void decrement() {
677 node_t* next(_node->link(_edge, node_t::prior_s));
678
679 if (is_leading(_edge))
680 _edge = forest_edge(next->link(forest_edge::trailing, node_t::next_s) != _node);
681 else
682 _edge = forest_edge(next == _node);
683
684 _node = next;
685 }
686
687 [[nodiscard]] auto equal(const forest_iterator& y) const -> bool {
688 return (_node == y._node) && (_edge == y._edge);
689 }
690
691 node_t* _node{nullptr};
692 forest_edge _edge{forest_edge::leading};
693
694 forest_iterator(node_t* node, forest_edge edge) : _node(node), _edge(edge) {}
695};
696
697/**************************************************************************************************/
698
699template <class T> // T is value_type
700struct forest_const_iterator {
701 using value_type = const T;
702 using difference_type = std::ptrdiff_t;
703 using reference = const T&;
704 using pointer = const T*;
705 using iterator_category = std::bidirectional_iterator_tag;
706
707 forest_const_iterator() = default;
708
709 forest_const_iterator(const forest_const_iterator& x) : _node(x._node), _edge(x._edge) {}
710
711 auto operator=(const forest_const_iterator&) -> forest_const_iterator& = default;
712
713 forest_const_iterator(const forest_iterator<T>& x) : _node(x._node), _edge(x._edge) {}
714
715 [[nodiscard]] auto edge() const -> forest_edge { return _edge; }
716 auto edge() -> forest_edge& { return _edge; }
717 [[nodiscard]] auto equal_node(forest_const_iterator const& y) const -> bool {
718 return _node == y._node;
719 }
720
721 auto operator*() const -> reference { return dereference(); }
722 auto operator->() const -> pointer { return &dereference(); }
723 auto operator++() -> auto& {
724 increment();
725 return *this;
726 }
727 auto operator++(int) -> forest_const_iterator {
728 auto result{*this};
729 increment();
730 return result;
731 }
732 auto operator--() -> auto& {
733 decrement();
734 return *this;
735 }
736 auto operator--(int) -> forest_const_iterator {
737 auto result{*this};
738 decrement();
739 return result;
740 }
741
742 friend auto operator==(const forest_const_iterator& a, const forest_const_iterator& b) -> bool {
743 return a.equal(b);
744 }
745 friend auto operator!=(const forest_const_iterator& a, const forest_const_iterator& b) -> bool {
746 return !(a == b);
747 }
748
749private:
750 template <class>
751 friend class stlab::forest;
752 template <class>
753 friend struct forest_const_iterator;
754 friend struct unsafe::set_next_fn<forest_const_iterator>;
755
756 using node_t = const node<T>;
757
758 [[nodiscard]] auto dereference() const -> reference { return _node->_data; }
759
760 void increment() {
761 node_t* next(_node->link(_edge, node_t::next_s));
762
763 if (is_leading(_edge))
764 _edge = forest_edge(next != _node);
765 else
766 _edge = forest_edge(next->link(forest_edge::leading, node_t::prior_s) == _node);
767
768 _node = next;
769 }
770
771 void decrement() {
772 node_t* next(_node->link(_edge, node_t::prior_s));
773
774 if (is_leading(_edge))
775 _edge = forest_edge(next->link(forest_edge::trailing, node_t::next_s) != _node);
776 else
777 _edge = forest_edge(next == _node);
778
779 _node = next;
780 }
781
782 [[nodiscard]] auto equal(const forest_const_iterator& y) const -> bool {
783 return (_node == y._node) && (_edge == y._edge);
784 }
785
786 node_t* _node{nullptr};
787 forest_edge _edge{forest_edge::leading};
788
789 forest_const_iterator(node_t* node, forest_edge edge) : _node(node), _edge(edge) {}
790};
791
792/**************************************************************************************************/
793
794} // namespace detail
795
796/**************************************************************************************************/
797
798namespace unsafe {
799
800/**************************************************************************************************/
801
802template <class T> // T is node<T>
803struct set_next_fn<detail::forest_iterator<T>> {
804 void operator()(detail::forest_iterator<T> x, detail::forest_iterator<T> y) const {
805 using node_t = typename detail::node<T>;
806
807 x._node->link(x.edge(), node_t::next_s) = y._node;
808 y._node->link(y.edge(), node_t::prior_s) = x._node;
809 }
810};
811
812/**************************************************************************************************/
813
814} // namespace unsafe
815
816/**************************************************************************************************/
817
834template <class T>
835class forest {
836private:
837 using node_t = detail::node<T>;
838 friend class child_adaptor<forest<T>>;
839
840public:
841 // types
842 using reference = T&;
843 using const_reference = const T&;
844 using iterator = detail::forest_iterator<T>;
845 using const_iterator = detail::forest_const_iterator<T>;
846 using size_type = std::size_t;
847 using difference_type = std::ptrdiff_t;
848 using value_type = T;
849 using pointer = T*;
850 using const_pointer = const T*;
851 using reverse_iterator = reverse_fullorder_iterator<iterator>;
852 using const_reverse_iterator = reverse_fullorder_iterator<const_iterator>;
853
854 /* qualification needed since: A name N used in a class S shall refer to the same declaration
855 in its context and when re-evaluated in the completed scope of
856 S. */
857 using child_iterator = stlab::child_iterator<iterator>;
858 using const_child_iterator = stlab::child_iterator<const_iterator>;
859 using reverse_child_iterator = std::reverse_iterator<child_iterator>;
860
861 using preorder_iterator = edge_iterator<iterator, forest_edge::leading>;
862 using const_preorder_iterator = edge_iterator<const_iterator, forest_edge::leading>;
863 using postorder_iterator = edge_iterator<iterator, forest_edge::trailing>;
864 using const_postorder_iterator = edge_iterator<const_iterator, forest_edge::trailing>;
865
866 forest() = default;
867 ~forest() { clear(); }
868
869 forest(const forest& x) {
870 insert(end(), const_child_iterator(x.begin()), const_child_iterator(x.end()));
871 }
872 forest(forest&& x) noexcept : forest() { splice(end(), x); }
873 auto operator=(const forest& x) -> forest& {
874 // self-assignment is not allowed to disable cert-oop54-cpp warning (and is likely a bug)
875 assert(this != &x && "self-assignment is not allowed");
876 return *this = forest(x);
877 }
878
879 auto operator=(forest&& x) noexcept -> forest& {
880 auto tmp{std::move(x)}; // this is `release()`
881 clear(); // these two lines are `reset()`
882 splice(end(), tmp);
883 return *this;
884 }
885
886 void swap(forest& x) noexcept { std::swap(*this, x); }
887
896 auto size() const -> size_type;
897 auto max_size() const -> size_type { return size_type(-1); }
898 auto size_valid() const -> bool { return _size != 0 || empty(); }
899 auto empty() const -> bool {
900 return begin() == end();
901 } // Don't test size which may be expensive
902
903 // iterators
904 auto root() -> iterator { return iterator(tail(), forest_edge::leading); }
905 auto root() const -> const_iterator { return const_iterator(tail(), forest_edge::leading); }
906
907 auto begin() -> iterator { return ++root(); }
908 auto end() -> iterator { return iterator(tail(), forest_edge::trailing); }
909 auto begin() const -> const_iterator { return ++root(); }
910 auto end() const -> const_iterator { return const_iterator(tail(), forest_edge::trailing); }
911
912 auto rbegin() -> reverse_iterator { return reverse_iterator(end()); }
913 auto rend() -> reverse_iterator { return reverse_iterator(begin()); }
914 auto rbegin() const -> const_reverse_iterator { return const_reverse_iterator(end()); }
915 auto rend() const -> const_reverse_iterator { return const_reverse_iterator(begin()); }
916
917 auto front() -> reference {
918 assert(!empty());
919 return *begin();
920 }
921 auto front() const -> const_reference {
922 assert(!empty());
923 return *begin();
924 }
925 auto back() -> reference {
926 assert(!empty());
927 return *(--end());
928 }
929 auto back() const -> const_reference {
930 assert(!empty());
931 return *(--end());
932 }
933
934 // modifiers
935 void clear() {
936 erase(begin(), end());
937 assert(empty()); // Make sure our erase is correct
938 }
939
945 auto erase(const iterator& position) -> iterator;
946
951 auto erase(const iterator& first, const iterator& last) -> iterator;
952
953 auto insert(const iterator& position, T x) -> iterator {
954 iterator result(new node_t(std::move(x)), forest_edge::leading);
955
956 if (size_valid()) ++_size;
957
958 unsafe::set_next(std::prev(position), result);
959 unsafe::set_next(std::next(result), position);
960
961 return result;
962 }
963
964 void push_front(const T& x) { insert(begin(), x); }
965 void push_back(const T& x) { insert(end(), x); }
966 void pop_front() {
967 assert(!empty());
968 erase(begin());
969 }
970 void pop_back() {
971 assert(!empty());
972 erase(--end());
973 }
974
975 auto insert(iterator position,
976 const const_child_iterator& first,
977 const const_child_iterator& last) -> iterator;
978
979 auto splice(const iterator& position, forest<T>& x) -> iterator;
980 auto splice(const iterator& position, forest<T>& x, iterator i) -> iterator;
981 auto splice(const iterator& position, forest<T>& x, child_iterator first, child_iterator last)
982 -> iterator;
983 auto splice(const iterator& position,
984 forest<T>& x,
985 const child_iterator& first,
986 const child_iterator& last,
987 size_type count) -> iterator;
988
989 auto insert_parent(child_iterator front, child_iterator back, const T& x) -> iterator;
990 void reverse(child_iterator first, child_iterator last);
991
992private:
993 friend struct detail::forest_iterator<value_type>;
994 friend struct detail::forest_const_iterator<value_type>;
995 friend struct unsafe::set_next_fn<iterator>;
996
997 mutable std::atomic<size_type> _size{0};
998 detail::node_base<node_t> _tail;
999
1000 auto tail() -> node_t* { return static_cast<node_t*>(&_tail); }
1001 auto tail() const -> const node_t* { return static_cast<const node_t*>(&_tail); }
1002};
1003
1004/**************************************************************************************************/
1005
1006template <class T>
1007auto operator==(const forest<T>& x, const forest<T>& y) -> bool {
1008 if (x.size() != y.size()) return false;
1009
1010 for (auto first(x.begin()), last(x.end()), pos(y.begin()); first != last; ++first, ++pos) {
1011 if (first.edge() != pos.edge()) return false;
1012 if (is_leading(first) && (*first != *pos)) return false;
1013 }
1014
1015 return true;
1016}
1017
1018template <class T>
1019auto operator!=(const forest<T>& x, const forest<T>& y) -> bool {
1020 return !(x == y);
1021}
1022
1023/**************************************************************************************************/
1024
1025namespace unsafe {
1026
1027/**************************************************************************************************/
1028
1029template <class I> // I models a FullorderIterator
1031 void operator()(const child_iterator<I>& x, const child_iterator<I>& y) {
1032 unsafe::set_next(pivot_of(x.base()), y.base());
1033 }
1034};
1035
1036/**************************************************************************************************/
1037
1038} // namespace unsafe
1039
1040/**************************************************************************************************/
1041
1042template <class T>
1043auto forest<T>::size() const -> size_type {
1044 if (!size_valid()) {
1045 const_preorder_iterator first(begin());
1046 const_preorder_iterator last(end());
1047
1048 _size = size_type(std::distance(first, last));
1049 }
1050
1051 return _size;
1052}
1053
1054/**************************************************************************************************/
1055
1056template <class T>
1057auto forest<T>::erase(const iterator& first, const iterator& last) -> iterator {
1058 difference_type stack_depth(0);
1059 iterator position(first);
1060
1061 while (position != last) {
1062 if (position.edge() == forest_edge::leading) {
1063 ++stack_depth;
1064 ++position;
1065 } else {
1066 if (stack_depth > 0)
1067 position = erase(position);
1068 else
1069 ++position;
1070 stack_depth = std::max<difference_type>(0, stack_depth - 1);
1071 }
1072 }
1073 return last;
1074}
1075
1076/**************************************************************************************************/
1077
1078template <class T>
1079auto forest<T>::erase(const iterator& position) -> iterator {
1080 /*
1081 NOTE (sparent) : After the first call to set_next() the invariants of the forest are
1082 violated and we can't determine leading/trailing if we navigate from the affected node.
1083 So we gather all the iterators up front then do the set_next calls.
1084 */
1085
1086 if (size_valid()) --_size;
1087
1088 iterator leading_prior(std::prev(leading_of(position)));
1089 iterator leading_next(std::next(leading_of(position)));
1090 iterator trailing_prior(std::prev(trailing_of(position)));
1091 iterator trailing_next(std::next(trailing_of(position)));
1092
1093 if (has_children(position)) {
1094 unsafe::set_next(leading_prior, leading_next);
1095 unsafe::set_next(trailing_prior, trailing_next);
1096 } else {
1097 unsafe::set_next(leading_prior, trailing_next);
1098 }
1099
1100 delete position._node;
1101
1102 return is_leading(position) ? std::next(leading_prior) : trailing_next;
1103}
1104
1105/**************************************************************************************************/
1106
1107template <class T>
1108auto forest<T>::splice(const iterator& position, forest<T>& x) -> iterator {
1109 return splice(position, x, child_iterator(x.begin()), child_iterator(x.end()),
1110 x.size_valid() ? x.size() : 0);
1111}
1112
1113/**************************************************************************************************/
1114
1115template <class T>
1116auto forest<T>::splice(const iterator& position, forest<T>& x, iterator i) -> iterator {
1117 i.edge() = forest_edge::leading;
1118 return splice(position, x, child_iterator(i), ++child_iterator(i), has_children(i) ? 0 : 1);
1119}
1120
1121/**************************************************************************************************/
1122
1123template <class T>
1124auto forest<T>::insert(iterator pos, const const_child_iterator& f, const const_child_iterator& l)
1125 -> iterator {
1126 for (const_iterator first(f.base()), last(l.base()); first != last; ++first, ++pos) {
1127 if (is_leading(first)) pos = insert(pos, *first);
1128 }
1129
1130 return pos;
1131}
1132
1133/**************************************************************************************************/
1134
1135template <class T>
1136auto forest<T>::splice(const iterator& position,
1137 forest<T>& x,
1138 const child_iterator& first,
1139 const child_iterator& last,
1140 size_type count) -> iterator {
1141 if (first == last || first.base() == position) return position;
1142
1143 if (&x != this) {
1144 if (count) {
1145 if (size_valid()) _size += count;
1146 if (x.size_valid()) x._size -= count;
1147 } else {
1148 _size = 0;
1149 x._size = 0;
1150 }
1151 }
1152
1153 iterator back(std::prev(last.base()));
1154
1155 unsafe::set_next(std::prev(first), last);
1156
1157 unsafe::set_next(std::prev(position), first.base());
1158 unsafe::set_next(back, position);
1159
1160 return first.base();
1161}
1162
1163/**************************************************************************************************/
1164
1165template <class T>
1166auto forest<T>::splice(const iterator& position,
1167 forest<T>& x,
1168 child_iterator first,
1169 child_iterator last) -> iterator {
1170 return splice(position, x, first, last, 0);
1171}
1172
1173/**************************************************************************************************/
1174
1175template <class T>
1176auto forest<T>::insert_parent(child_iterator first, child_iterator last, const T& x) ->
1177 typename forest<T>::iterator {
1178 iterator result(insert(last.base(), x));
1179 if (first == last) return result;
1180 splice(trailing_of(result), *this, first, child_iterator(result));
1181 return result;
1182}
1183
1184/**************************************************************************************************/
1185
1186template <class T>
1187void forest<T>::reverse(child_iterator first, child_iterator last) {
1188 iterator prior(first.base());
1189 --prior;
1190 first = unsafe::reverse_nodes(first, last);
1191 unsafe::set_next(prior, first.base());
1192}
1193
1194/**************************************************************************************************/
1195
1197template <class I> // I models FullorderIterator
1198auto child_begin(const I& x) -> child_iterator<I> {
1199 return child_iterator<I>(std::next(leading_of(x)));
1200}
1201
1202/**************************************************************************************************/
1203
1205template <class I> // I models FullorderIterator
1206auto child_end(const I& x) -> child_iterator<I> {
1207 return child_iterator<I>(trailing_of(x));
1208}
1209
1210/**************************************************************************************************/
1211
1214template <class Forest>
1215class child_adaptor {
1216public:
1217 using forest_type = Forest;
1218 using value_type = typename Forest::value_type;
1219 using iterator_type = typename Forest::iterator;
1220 using reference = typename Forest::reference;
1221 using const_reference = typename Forest::const_reference;
1222 using difference_type = typename Forest::difference_type;
1223 using iterator = typename Forest::child_iterator;
1224
1225 child_adaptor() = delete; // not defined
1226 child_adaptor(forest_type& f, iterator_type& i) : _forest(f), _iterator(i) {}
1227
1228 auto back() -> value_type& { return *(--child_end(_iterator)); }
1229 auto front() -> value_type& { return *(child_begin(_iterator)); }
1230
1231 void push_back(const value_type& x) { _forest.insert(child_end(_iterator).base(), x); }
1232 void push_front(const value_type& x) { _forest.insert(child_begin(_iterator).base(), x); }
1233
1234 void pop_back() { _forest.erase(--child_end(_iterator).base()); }
1235 void pop_front() { _forest.erase(child_begin(_iterator).base()); }
1236
1237private:
1238 forest_type& _forest;
1239 iterator_type& _iterator;
1240};
1241
1242/**************************************************************************************************/
1243
1245template <class I>
1247 I _f;
1248 I _l;
1249
1250 [[nodiscard]] auto begin() const { return _f; }
1251 [[nodiscard]] auto end() const { return _l; }
1252};
1253
1254/**************************************************************************************************/
1255
1257template <class I> // I models FullorderIterator
1258auto child_range(const I& x) {
1260}
1261
1262/**************************************************************************************************/
1263
1265template <class R, typename P> // R models FullorderRange
1266auto filter_fullorder_range(R& x, P p) {
1268
1269 return forest_range<iterator>{iterator(std::begin(x), std::end(x), p),
1270 iterator(std::end(x), std::end(x), p)};
1271}
1272
1274template <class R, typename P> // R models FullorderRange
1275auto filter_fullorder_range(const R& x, P p) {
1277
1278 return forest_range<iterator>{iterator(std::begin(x), std::end(x), p),
1279 iterator(std::end(x), std::end(x), p)};
1280}
1281
1282/**************************************************************************************************/
1283
1285template <class R> // R models FullorderRange
1288
1289 return forest_range<iterator>{iterator(std::end(x)), iterator(std::begin(x))};
1290}
1291
1293template <class R> // R models FullorderRange
1294auto reverse_fullorder_range(const R& x) {
1296
1297 return forest_range<iterator>{iterator(std::end(x)), iterator(std::begin(x))};
1298}
1299
1300/**************************************************************************************************/
1301
1303template <class R> // R models FullorderRange
1304auto depth_range(R& x) {
1306
1307 return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))};
1308}
1309
1311template <class R> // R models FullorderRange
1312auto depth_range(const R& x) {
1314
1315 return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))};
1316}
1317
1318/**************************************************************************************************/
1319
1321template <class R> // R models FullorderRange
1324
1325 return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))};
1326}
1327
1329template <class R> // R models FullorderRange
1330auto postorder_range(const R& x) {
1332
1333 return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))};
1334}
1335
1336/**************************************************************************************************/
1337
1338template <class R> // R models FullorderRange
1339auto preorder_range(R& x) {
1340 using iterator = edge_iterator<typename R::iterator, forest_edge::leading>;
1341
1342 return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))};
1343}
1344
1346template <class R> // R models FullorderRange
1347auto preorder_range(const R& x) {
1349
1350 return forest_range<iterator>{iterator(std::begin(x)), iterator(std::end(x))};
1351}
1352
1353/**************************************************************************************************/
1354
1356
1357STLAB_VERSION_NAMESPACE_END()
1358} // namespace stlab
1359
1360/**************************************************************************************************/
1361
1362#endif // STLAB_FOREST_HPP
1363
1364/**************************************************************************************************/
Presents the children of a node (given by a fullorder iterator into forest) as a small sequence-like ...
Definition forest.hpp:1215
Hierarchical, node-based container: a forest (ordered sequence of trees) with fullorder iterators and...
Definition forest.hpp:835
auto find_edge(I x, forest_edge edge) -> I
Advances x forward until x.edge() == edge (or returns last such position).
Definition forest.hpp:210
constexpr auto is_trailing(forest_edge e)
True if e is a trailing-edge position.
Definition forest.hpp:111
auto find_edge_reverse(I x, forest_edge edge) -> I
Advances x backward until x.edge() == edge.
Definition forest.hpp:218
auto trailing_of(I i)
Positions i on the trailing edge of the same node.
Definition forest.hpp:94
auto postorder_range(R &x)
Postorder (trailing-edge) walk over x.
Definition forest.hpp:1322
constexpr auto pivot(forest_edge e)
Toggles a forest_edge between leading and trailing.
Definition forest.hpp:68
auto depth_range(R &x)
Fullorder walk with depth tracking over x (depth_fullorder_iterator).
Definition forest.hpp:1304
auto find_parent(I i) -> I
Returns the trailing-edge iterator of the parent of the subtree containing i.
Definition forest.hpp:130
auto erase(const iterator &position) -> iterator
Erases the node at position.
Definition forest.hpp:1079
auto child_end(const I &x) -> child_iterator< I >
One-past-last child iterator for the node referenced by x (half-open child sequence).
Definition forest.hpp:1206
auto child_begin(const I &x) -> child_iterator< I >
First child iterator for the node referenced by fullorder iterator x (may equal child_end).
Definition forest.hpp:1198
auto size() const -> size_type
Returns the number of nodes; when size_valid() is true, otherwise a linear walk.
Definition forest.hpp:1043
auto filter_fullorder_range(R &x, P p)
Range of filter_fullorder_iterator over x using predicate p.
Definition forest.hpp:1266
forest_edge
Leading and trailing visits in a fullorder walk of a node (see forest iterators).
Definition forest.hpp:60
auto leading_of(I i)
Positions i on the leading edge of the same node.
Definition forest.hpp:87
auto pivot_of(I i)
Returns a copy of i with its edge toggled (pivot).
Definition forest.hpp:78
auto reverse_fullorder_range(R &x)
Reverses the fullorder traversal of x (see reverse_fullorder_iterator).
Definition forest.hpp:1286
constexpr auto is_leading(forest_edge e)
True if e is a leading-edge position.
Definition forest.hpp:102
auto child_range(const I &x)
forest_range of child_iterator over the immediate children of the node at x.
Definition forest.hpp:1258
void set_next(const I &x, const I &y)
Sets the successor of the node referenced by x to y (via set_next_fn<I>).
Definition set_next.hpp:41
constexpr auto move(T &&t) noexcept -> std::remove_reference_t< T > &&
A standard move implementation but with a compile-time check for const types.
Definition utility.hpp:154
Definition reverse.hpp:39
auto reverse_nodes(I first, I last) -> I
Reverses the range [first, last) and returns the beginning of the reversed range such that [result,...
Definition reverse.hpp:70
Definition reverse.hpp:28
Reverse algorithms for iterators and intrusive forward / bidirectional sequences.
Intrusive forward/bidirectional iterator helpers (set_next, splice, skip).
Iterator over the child sequence of a node: adapts a fullorder iterator to visit only immediate child...
Definition forest.hpp:149
Fullorder iterator that tracks depth in the tree as it advances or retreats.
Definition forest.hpp:482
Fullorder iterator restricted to a single edge kind: visits only leading or trailing positions (e....
Definition forest.hpp:229
Fullorder iterator that visits only positions whose values satisfy predicate P (skipping others by ad...
Definition forest.hpp:287
Half-open range [begin, end) of forest iterators; used by child_range, preorder_range,...
Definition forest.hpp:1246
Reverses the direction of a fullorder walk while preserving edge semantics (bidirectional).
Definition forest.hpp:403
Hook for intrusive iterators: specialize to set the successor of the node at x to y.
Definition set_next.hpp:35