timemory 3.3.0
Modular C++ Toolkit for Performance Analysis and Logging. Profiling API and Tools for C, C++, CUDA, Fortran, and Python. The C++ template API is essentially a framework to creating tools: it is designed to provide a unifying interface for recording various performance measurements alongside data logging and interfaces to other tools.
graph.hpp
Go to the documentation of this file.
1// MIT License
2//
3// Copyright (c) 2020, The Regents of the University of California,
4// through Lawrence Berkeley National Laboratory (subject to receipt of any
5// required approvals from the U.S. Dept. of Energy). All rights reserved.
6//
7// Permission is hereby granted, free of charge, to any person obtaining a copy
8// of this software and associated documentation files (the "Software"), to
9// deal in the Software without restriction, including without limitation the
10// rights to use, copy, modify, merge, publish, distribute, sublicense, and
11// copies of the Software, and to permit persons to whom the Software is
12// furnished to do so, subject to the following conditions:
13//
14// The above copyright notice and this permission notice shall be included in
15// all copies or substantial portions of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23// IN THE SOFTWARE.
24
25#pragma once
26
32#include "timemory/tpls/cereal/cereal.hpp"
33#include "timemory/units.hpp"
34
35#include <cassert>
36#include <cstddef>
37#include <deque>
38#include <functional>
39#include <iomanip>
40#include <iostream>
41#include <iterator>
42#include <memory>
43#include <queue>
44#include <set>
45#include <stdexcept>
46#include <utility>
47#include <vector>
48
49//--------------------------------------------------------------------------------------//
50
51namespace tim
52{
53//======================================================================================//
54
55/// A node in the graph, combining links to other nodes as well as the actual
56/// data.
57template <typename T>
59{
60 // size: 5*4=20 bytes (on 32 bit arch), can be reduced by 8.
61public:
62 tgraph_node() = default;
63 ~tgraph_node() = default;
64 explicit tgraph_node(const T&); // NOLINT
65 explicit tgraph_node(T&&) noexcept;
66
67#if defined(TIMEMORY_WINDOWS) || defined(TIMEMORY_NVCC_COMPILER)
68 tgraph_node(const tgraph_node&) = default;
69 tgraph_node& operator=(const tgraph_node&) = default;
70#else
71 tgraph_node(const tgraph_node&) = delete;
73#endif
74
75 tgraph_node(tgraph_node&&) = default; // NOLINT
76 tgraph_node& operator=(tgraph_node&&) = default; // NOLINT
77
83 T data = T{};
84
85 //----------------------------------------------------------------------------------//
86 //
87 template <typename Archive>
88 void serialize(Archive& ar, const unsigned int)
89 {
90 ar(cereal::make_nvp("data", data));
91 }
92};
93
94//======================================================================================//
95
96template <typename T>
97tgraph_node<T>::tgraph_node(const T& val) // NOLINT
98: data(val) // NOLINT
99{}
100
101//--------------------------------------------------------------------------------------//
102
103template <typename T>
105: data(std::move(val))
106{}
107
108//======================================================================================//
109/// \class tim::graph
110/// \brief Arbitrary Graph / Tree (i.e. binary-tree but not binary). It is unlikely that
111/// this class will interacted with directly.
112///
113template <typename T, typename AllocatorT>
114class graph
115{
116protected:
119
120public:
121 /// Value of the data stored at a node.
122 using value_type = T;
123
124 class iterator_base;
125 class pre_order_iterator;
126 class sibling_iterator;
127
128 graph(); // empty constructor
129 graph(const T&); // constructor setting given element as head
130 graph(const iterator_base&);
132 graph(const this_type&) = delete;
133 graph(this_type&&) noexcept = default;
134 graph& operator=(const graph&) = delete;
135 graph& operator=(graph&&) noexcept = default;
136
137 /// Base class for iterators, only pointers stored, no traversal logic.
139 {
140 public:
141 typedef T value_type;
142 typedef T* pointer;
143 typedef T& reference;
144 typedef size_t size_type;
145 typedef ptrdiff_t difference_type;
146 typedef std::bidirectional_iterator_tag iterator_category;
147
148 iterator_base();
149 iterator_base(graph_node*);
150
151 iterator_base(const iterator_base&) = default;
152 iterator_base(iterator_base&&) noexcept = default;
153
154 public:
155 // public operators
156 iterator_base& operator=(const iterator_base&) = default;
157 iterator_base& operator=(iterator_base&&) noexcept = default;
158
159 operator bool() const { return node != nullptr; }
160
161 T& operator*() const;
162 T* operator->() const;
163
164 public:
165 // public member functions
166 /// When called, the next increment/decrement skips children of this
167 /// node.
168 void skip_children();
169 void skip_children(bool skip);
170 /// Number of children of the node pointed to by the iterator.
171 TIMEMORY_NODISCARD unsigned int number_of_children() const;
172
173 TIMEMORY_NODISCARD sibling_iterator begin() const;
174 TIMEMORY_NODISCARD sibling_iterator end() const;
175
176 public:
177 // public data member
178 graph_node* node = nullptr;
179
180 protected:
181 // protected data member
182 bool m_skip_current_children = false;
183 };
184
185 /// Depth-first iterator, first accessing the node, then its children.
187 {
188 public:
192 pre_order_iterator(const sibling_iterator&);
193
196
197 public:
198 // public operators
199 pre_order_iterator& operator=(const pre_order_iterator&) = default;
200 pre_order_iterator& operator=(pre_order_iterator&&) noexcept = default;
201
202 bool operator==(const pre_order_iterator&) const;
203 bool operator!=(const pre_order_iterator&) const;
204 pre_order_iterator& operator++();
205 pre_order_iterator& operator--();
206 pre_order_iterator operator++(int);
207 pre_order_iterator operator--(int);
208 pre_order_iterator& operator+=(unsigned int);
209 pre_order_iterator& operator-=(unsigned int);
210 pre_order_iterator operator+(unsigned int);
211
212 public:
213 // public member functions
215 };
216
217 /// The default iterator types throughout the graph class.
221
222 /// Iterator which traverses only the nodes which are siblings of each
223 /// other.
225 {
226 public:
227 sibling_iterator();
228 sibling_iterator(graph_node*);
229 sibling_iterator(const iterator_base&);
230
232 sibling_iterator(sibling_iterator&&) noexcept = default;
233
234 public:
235 // public operators
236 sibling_iterator& operator=(const sibling_iterator&) = default;
237 sibling_iterator& operator=(sibling_iterator&&) noexcept = default;
238
239 bool operator==(const sibling_iterator&) const;
240 bool operator!=(const sibling_iterator&) const;
241 sibling_iterator& operator++();
242 sibling_iterator& operator--();
243 sibling_iterator operator++(int);
244 sibling_iterator operator--(int);
245 sibling_iterator& operator+=(unsigned int);
246 sibling_iterator& operator-=(unsigned int);
247 sibling_iterator operator+(unsigned int);
248
249 public:
250 // public member functions
251 TIMEMORY_NODISCARD graph_node* range_first() const;
252 TIMEMORY_NODISCARD graph_node* range_last() const;
253
254 public:
255 // public data member
256 graph_node* m_parent;
257
258 private:
259 void m_set_parent();
260 };
261
262 /// Return iterator to the beginning of the graph.
263 TIMEMORY_NODISCARD inline pre_order_iterator begin() const;
264
265 /// Return iterator to the end of the graph.
266 TIMEMORY_NODISCARD inline pre_order_iterator end() const;
267
268 /// Return sibling iterator to the first child of given node.
269 static sibling_iterator begin(const iterator_base&);
270
271 /// Return sibling end iterator for children of given node.
272 static sibling_iterator end(const iterator_base&);
273
274 /// Return iterator to the parent of a node.
275 template <typename IterT>
276 static IterT parent(IterT);
277
278 /// Return iterator to the previous sibling of a node.
279 template <typename IterT>
280 static IterT previous_sibling(IterT);
281
282 /// Return iterator to the next sibling of a node.
283 template <typename IterT>
284 static IterT next_sibling(IterT);
285
286 /// Erase all nodes of the graph.
287 inline void clear();
288
289 /// Erase element at position pointed to by iterator, return incremented
290 /// iterator.
291 template <typename IterT>
292 inline IterT erase(IterT);
293
294 /// Erase all children of the node pointed to by iterator.
295 inline void erase_children(const iterator_base&);
296
297 /// Insert empty node as last/first child of node pointed to by position.
298 template <typename IterT>
299 inline IterT append_child(IterT position);
300 template <typename IterT>
301 inline IterT prepend_child(IterT position);
302
303 /// Insert node as last/first child of node pointed to by position.
304 template <typename IterT>
305 inline IterT append_child(IterT position, const T& x);
306 template <typename IterT>
307 inline IterT append_child(IterT position, T&& x);
308 template <typename IterT>
309 inline IterT prepend_child(IterT position, const T& x);
310 template <typename IterT>
311 inline IterT prepend_child(IterT position, T&& x);
312
313 /// Append the node (plus its children) at other_position as last/first
314 /// child of position.
315 template <typename IterT>
316 inline IterT append_child(IterT position, IterT other_position);
317 template <typename IterT>
318 inline IterT prepend_child(IterT position, IterT other_position);
319
320 /// Append the nodes in the from-to range (plus their children) as
321 /// last/first children of position.
322 template <typename IterT>
323 inline IterT append_children(IterT position, sibling_iterator from,
324 const sibling_iterator& to);
325 template <typename IterT>
326 inline IterT prepend_children(IterT position, sibling_iterator from,
327 sibling_iterator to);
328
329 /// Short-hand to insert topmost node in otherwise empty graph.
330 inline pre_order_iterator set_head(const T& x);
332
333 /// Insert node as previous sibling of node pointed to by position.
334 template <typename IterT>
335 inline IterT insert(IterT position, const T& x);
336 template <typename IterT>
337 inline IterT insert(IterT position, T&& x);
338
339 /// Specialisation of previous member.
340 inline sibling_iterator insert(sibling_iterator position, const T& x);
341
342 /// Insert node (with children) pointed to by subgraph as previous sibling
343 /// of node pointed to by position. Does not change the subgraph itself (use
344 /// move_in or move_in_below for that).
345 template <typename IterT>
346 inline IterT insert_subgraph(IterT position, const iterator_base& subgraph);
347
348 /// Insert node as next sibling of node pointed to by position.
349 template <typename IterT>
350 inline IterT insert_after(IterT position, const T& x);
351 template <typename IterT>
352 inline IterT insert_after(IterT position, T&& x);
353
354 /// Insert node (with children) pointed to by subgraph as next sibling of
355 /// node pointed to by position.
356 template <typename IterT>
357 inline IterT insert_subgraph_after(IterT position, const iterator_base& subgraph);
358
359 /// Replace node at 'position' with other node (keeping same children);
360 /// 'position' becomes invalid.
361 template <typename IterT>
362 inline IterT replace(IterT position, const T& x);
363
364 template <typename IterT>
365 inline IterT replace(IterT position, T&& x);
366
367 /// Replace node at 'position' with subgraph starting at 'from' (do not
368 /// erase subgraph at 'from'); see above.
369 template <typename IterT>
370 inline IterT replace(IterT position, const iterator_base& from);
371
372 /// Replace string of siblings (plus their children) with copy of a new
373 /// string (with children); see above
374 inline sibling_iterator replace(sibling_iterator orig_begin,
375 const sibling_iterator& orig_end,
376 sibling_iterator new_begin,
377 const sibling_iterator& new_end);
378
379 /// Move all children of node at 'position' to be siblings, returns
380 /// position.
381 template <typename IterT>
382 inline IterT flatten(IterT position);
383
384 /// Move nodes in range to be children of 'position'.
385 template <typename IterT>
386 inline IterT reparent(IterT position, sibling_iterator begin,
387 const sibling_iterator& end);
388 /// Move all child nodes of 'from' to be children of 'position'.
389 template <typename IterT>
390 inline IterT reparent(IterT position, IterT from);
391
392 /// Replace node with a new node, making the old node (plus subgraph) a
393 /// child of the new node.
394 template <typename IterT>
395 inline IterT wrap(IterT position, const T& x);
396
397 /// Replace the range of sibling nodes (plus subgraphs), making these
398 /// children of the new node.
399 template <typename IterT>
400 inline IterT wrap(IterT from, IterT to, const T& x);
401
402 /// Move 'source' node (plus its children) to become the next sibling of
403 /// 'target'.
404 template <typename IterT>
405 inline IterT move_after(IterT target, IterT source);
406
407 /// Move 'source' node (plus its children) to become the previous sibling of
408 /// 'target'.
409 template <typename IterT>
410 inline IterT move_before(IterT target, IterT source);
412
413 /// Move 'source' node (plus its children) to become the node at 'target'
414 /// (erasing the node at 'target').
415 template <typename IterT>
416 inline IterT move_ontop(IterT target, IterT source);
417
418 /// Extract the subgraph starting at the indicated node, removing it from
419 /// the original graph.
421
422 /// Inverse of take_out: inserts the given graph as previous sibling of
423 /// indicated node by a move operation, that is, the given graph becomes
424 /// empty. Returns iterator to the top node.
425 template <typename IterT>
426 inline IterT move_in(IterT, graph&);
427
428 /// As above, but now make the graph a child of the indicated node.
429 template <typename IterT>
430 inline IterT move_in_below(IterT, graph&);
431
432 /// As above, but now make the graph the nth child of the indicated node (if
433 /// possible).
434 template <typename IterT>
435 inline IterT move_in_as_nth_child(IterT, size_t, graph&);
436
437 /// Merge with other graph, creating new branches and leaves only if they
438 /// are not already present.
439 inline void merge(const sibling_iterator&, const sibling_iterator&, sibling_iterator,
440 const sibling_iterator&, bool duplicate_leaves = false,
441 bool first = false);
442
443 /// Reduce duplicate nodes
444 template <
445 typename ComparePred = std::function<bool(sibling_iterator, sibling_iterator)>,
446 typename ReducePred = std::function<void(sibling_iterator, sibling_iterator)>>
447 inline void reduce(
448 const sibling_iterator&, const sibling_iterator&, std::set<sibling_iterator>&,
449 ComparePred&& = [](sibling_iterator lhs,
450 sibling_iterator rhs) { return (*lhs == *rhs); },
451 ReducePred&& = [](sibling_iterator lhs, sibling_iterator rhs) { *lhs += *rhs; });
452
453 /// Compare two ranges of nodes (compares nodes as well as graph structure).
454 template <typename IterT>
455 inline bool equal(const IterT& one, const IterT& two, const IterT& three) const;
456 template <typename IterT, typename BinaryPredicate>
457 inline bool equal(const IterT& one, const IterT& two, const IterT& three,
458 BinaryPredicate) const;
459 template <typename IterT>
460 inline bool equal_subgraph(const IterT& one, const IterT& two) const;
461 template <typename IterT, typename BinaryPredicate>
462 inline bool equal_subgraph(const IterT& one, const IterT& two, BinaryPredicate) const;
463
464 /// Extract a new graph formed by the range of siblings plus all their
465 /// children.
466 TIMEMORY_NODISCARD inline graph subgraph(sibling_iterator from,
467 sibling_iterator to) const;
468 inline void subgraph(graph&, sibling_iterator from, sibling_iterator to) const;
469
470 /// Exchange the node (plus subgraph) with its sibling node (do nothing if
471 /// no sibling present).
472 inline void swap(sibling_iterator it);
473
474 /// Exchange two nodes (plus subgraphs). The iterators will remain valid and
475 /// keep pointing to the same nodes, which now sit at different locations in
476 /// the graph.
477 inline void swap(iterator, iterator);
478
479 /// Count the total number of nodes.
480 TIMEMORY_NODISCARD inline size_t size() const;
481
482 /// Check if graph is empty.
483 TIMEMORY_NODISCARD inline bool empty() const;
484
485 /// Compute the depth to the root or to a fixed other iterator.
486 static int depth(const iterator_base&);
487 static int depth(const iterator_base&, const iterator_base&);
488
489 /// Determine the maximal depth of the graph. An empty graph has
490 /// max_depth=-1.
491 TIMEMORY_NODISCARD inline int max_depth() const;
492
493 /// Determine the maximal depth of the graph with top node at the given
494 /// position.
495 TIMEMORY_NODISCARD inline int max_depth(const iterator_base&) const;
496
497 /// Count the number of children of node at position.
498 static unsigned int number_of_children(const iterator_base&);
499
500 /// Count the number of siblings (left and right) of node at iterator. Total
501 /// nodes at this level is +1.
502 TIMEMORY_NODISCARD inline unsigned int number_of_siblings(const iterator_base&) const;
503
504 /// Determine whether node at position is in the subgraphs with root in the
505 /// range.
506 TIMEMORY_NODISCARD inline bool is_in_subgraph(const iterator_base& position,
507 const iterator_base& begin,
508 const iterator_base& end) const;
509
510 /// Determine whether the iterator is an 'end' iterator and thus not
511 /// actually pointing to a node.
512 TIMEMORY_NODISCARD inline bool is_valid(const iterator_base&) const;
513
514 /// Determine whether the iterator is one of the 'head' nodes at the top
515 /// level, i.e. has no parent.
516 static bool is_head(const iterator_base&);
517
518 /// Determine the index of a node in the range of siblings to which it
519 /// belongs.
520 TIMEMORY_NODISCARD inline unsigned int index(sibling_iterator it) const;
521
522 /// Inverse of 'index': return the n-th child of the node at position.
523 static sibling_iterator child(const iterator_base& position, unsigned int);
524
525 /// Return iterator to the sibling indicated by index
526 TIMEMORY_NODISCARD inline sibling_iterator sibling(const iterator_base& position,
527 unsigned int) const;
528
529 template <typename Archive>
530 void serialize(Archive& ar, const unsigned int)
531 {
532 for(auto itr = begin(); itr != end(); ++itr)
533 ar(cereal::make_nvp("node", *itr));
534 }
535
536 void steal_resources(this_type& rhs) { m_stolen_alloc.emplace_back(rhs.m_alloc); }
537
538 graph_node* head = nullptr; // head/feet are always dummy; if an iterator
539 graph_node* feet = nullptr; // points to them it is invalid
540
541private:
542 inline void m_head_initialize();
543
544private:
545 using allocator_traits = std::allocator_traits<AllocatorT>;
546 using allocator_pointer = std::shared_ptr<AllocatorT>;
547 allocator_pointer m_alloc = data::shared_stateful_allocator<AllocatorT>::request();
548 std::vector<allocator_pointer> m_stolen_alloc = {};
549};
550
551//======================================================================================//
552// Graph
553//--------------------------------------------------------------------------------------//
554
555template <typename T, typename AllocatorT>
557{
558 m_head_initialize();
559}
560
561//--------------------------------------------------------------------------------------//
562
563template <typename T, typename AllocatorT>
565{
566 m_head_initialize();
567 set_head(x);
568}
569
570//--------------------------------------------------------------------------------------//
571
572template <typename T, typename AllocatorT>
574{
575 m_head_initialize();
576 set_head((*other));
577 replace(begin(), other);
578}
579
580//--------------------------------------------------------------------------------------//
581
582template <typename T, typename AllocatorT>
584{
585 clear();
586 if(m_alloc)
587 {
590 allocator_traits::deallocate(*m_alloc, head, 1);
591 allocator_traits::deallocate(*m_alloc, feet, 1);
592 }
593 while(!m_stolen_alloc.empty())
594 {
595 auto _v = m_stolen_alloc.back();
596 m_stolen_alloc.pop_back();
598 }
600}
601
602//--------------------------------------------------------------------------------------//
603
604template <typename T, typename AllocatorT>
605void
607{
608 head = allocator_traits::allocate(*m_alloc, 1, nullptr); // MSVC does not have
609 // default second argument
610 feet = allocator_traits::allocate(*m_alloc, 1, nullptr);
611 allocator_traits::construct(*m_alloc, head, std::move(tgraph_node<T>{}));
612 allocator_traits::construct(*m_alloc, feet, std::move(tgraph_node<T>{}));
613
614 head->parent = nullptr;
615 head->first_child = nullptr;
616 head->last_child = nullptr;
617 head->prev_sibling = nullptr; // head;
618 head->next_sibling = feet; // head;
619
620 feet->parent = nullptr;
621 feet->first_child = nullptr;
622 feet->last_child = nullptr;
624 feet->next_sibling = nullptr;
625}
626
627//--------------------------------------------------------------------------------------//
628
629template <typename T, typename AllocatorT>
630void
632{
633 if(head)
634 {
635 while(head->next_sibling != feet)
637 }
638}
639
640//--------------------------------------------------------------------------------------//
641
642template <typename T, typename AllocatorT>
643void
645{
646 if(it.node == nullptr)
647 return;
648
649 graph_node* cur = it.node->first_child;
650
651 if(cur)
652 {
653 while(cur->next_sibling && cur->next_sibling != feet)
655 }
656
657 it.node->first_child = nullptr;
658 it.node->last_child = nullptr;
659}
660
661//--------------------------------------------------------------------------------------//
662
663template <typename T, typename AllocatorT>
664template <typename IterT>
665IterT
667{
668 graph_node* cur = it.node;
669 assert(cur != head);
670 assert(cur != feet);
671 if(cur == head || cur == feet)
672 return it;
673 IterT ret = it;
674 // ret.skip_children();
675 ++ret;
676 erase_children(it);
677 if(cur->parent && cur->prev_sibling == nullptr)
678 {
679 cur->parent->first_child = cur->next_sibling;
680 }
681 else
682 {
683 cur->prev_sibling->next_sibling = cur->next_sibling;
684 }
685
686 if(cur->parent && cur->next_sibling == nullptr)
687 {
688 cur->parent->last_child = cur->prev_sibling;
689 }
690 else
691 {
692 cur->next_sibling->prev_sibling = cur->prev_sibling;
693 }
694
695 if(m_alloc)
696 {
697 allocator_traits::destroy(*m_alloc, cur);
698 allocator_traits::deallocate(*m_alloc, cur, 1);
699 }
700 it.node = nullptr;
701 return ret;
702}
703
704//--------------------------------------------------------------------------------------//
705
706template <typename T, typename AllocatorT>
709{
711}
712
713//--------------------------------------------------------------------------------------//
714
715template <typename T, typename AllocatorT>
718{
719 return pre_order_iterator(feet);
720}
721
722//--------------------------------------------------------------------------------------//
723
724template <typename T, typename AllocatorT>
727{
728 assert(pos.node != nullptr);
729 if(pos.node->first_child == nullptr)
730 {
731 return end(pos);
732 }
733 return pos.node->first_child;
734}
735
736//--------------------------------------------------------------------------------------//
737
738template <typename T, typename AllocatorT>
741{
742 sibling_iterator ret(nullptr);
743 ret.m_parent = pos.node;
744 return ret;
745}
746
747//--------------------------------------------------------------------------------------//
748
749template <typename T, typename AllocatorT>
750template <typename IterT>
751IterT
753{
754 assert(position.node != nullptr);
755 return IterT(position.node->parent);
756}
757
758//--------------------------------------------------------------------------------------//
759
760template <typename T, typename AllocatorT>
761template <typename IterT>
762IterT
764{
765 assert(position.node != nullptr);
766 IterT ret(position);
767 ret.node = position.node->prev_sibling;
768 return ret;
769}
770
771//--------------------------------------------------------------------------------------//
772
773template <typename T, typename AllocatorT>
774template <typename IterT>
775IterT
777{
778 assert(position.node != nullptr);
779 IterT ret(position);
780 ret.node = position.node->next_sibling;
781 return ret;
782}
783
784//--------------------------------------------------------------------------------------//
785
786template <typename T, typename AllocatorT>
787template <typename IterT>
788IterT
790{
791 assert(position.node != head);
792 assert(position.node != feet);
793 assert(position.node);
794
795 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
796 allocator_traits::construct(*m_alloc, tmp, std::move(tgraph_node<T>{}));
797 tmp->first_child = nullptr;
798 tmp->last_child = nullptr;
799
800 tmp->parent = position.node;
801 if(position.node->last_child != nullptr)
802 {
803 position.node->last_child->next_sibling = tmp;
804 }
805 else
806 {
807 position.node->first_child = tmp;
808 }
809 tmp->prev_sibling = position.node->last_child;
810 position.node->last_child = tmp;
811 tmp->next_sibling = nullptr;
812 return tmp;
813}
814
815//--------------------------------------------------------------------------------------//
816
817template <typename T, typename AllocatorT>
818template <typename IterT>
819IterT
821{
822 assert(position.node != head);
823 assert(position.node != feet);
824 assert(position.node);
825
826 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
827 allocator_traits::construct(*m_alloc, tmp, std::move(tgraph_node<T>{}));
828 tmp->first_child = nullptr;
829 tmp->last_child = nullptr;
830
831 tmp->parent = position.node;
832 if(position.node->first_child != nullptr)
833 {
834 position.node->first_child->prev_sibling = tmp;
835 }
836 else
837 {
838 position.node->last_child = tmp;
839 }
840 tmp->next_sibling = position.node->first_child;
841 position.node->prev_child = tmp;
842 tmp->prev_sibling = nullptr;
843 return tmp;
844}
845
846//--------------------------------------------------------------------------------------//
847
848template <typename T, typename AllocatorT>
849template <typename IterT>
850IterT
851graph<T, AllocatorT>::append_child(IterT position, const T& x)
852{
853 // If your program fails here you probably used 'append_child' to add the
854 // top node to an empty graph. From version 1.45 the top element should be
855 // added using 'insert'. See the documentation for further information, and
856 // sorry about the API change.
857 assert(position.node != head);
858 assert(position.node != feet);
859 assert(position.node);
860
861 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
862 allocator_traits::construct(*m_alloc, tmp, x);
863 tmp->first_child = nullptr;
864 tmp->last_child = nullptr;
865
866 tmp->parent = position.node;
867 if(position.node->last_child != nullptr)
868 {
869 position.node->last_child->next_sibling = tmp;
870 }
871 else
872 {
873 position.node->first_child = tmp;
874 }
875 tmp->prev_sibling = position.node->last_child;
876 position.node->last_child = tmp;
877 tmp->next_sibling = nullptr;
878 return tmp;
879}
880
881//--------------------------------------------------------------------------------------//
882
883template <typename T, typename AllocatorT>
884template <typename IterT>
885IterT
887{
888 assert(position.node != head);
889 assert(position.node != feet);
890 assert(position.node);
891
892 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
893 allocator_traits::construct(*m_alloc, tmp, std::forward<T>(x));
894
895 tmp->first_child = nullptr;
896 tmp->last_child = nullptr;
897
898 tmp->parent = position.node;
899 if(position.node->last_child != nullptr)
900 {
901 position.node->last_child->next_sibling = tmp;
902 }
903 else
904 {
905 position.node->first_child = tmp;
906 }
907 tmp->prev_sibling = position.node->last_child;
908 position.node->last_child = tmp;
909 tmp->next_sibling = nullptr;
910 return tmp;
911}
912
913//--------------------------------------------------------------------------------------//
914
915template <typename T, typename AllocatorT>
916template <typename IterT>
917IterT
918graph<T, AllocatorT>::prepend_child(IterT position, const T& x)
919{
920 assert(position.node != head);
921 assert(position.node != feet);
922 assert(position.node);
923
924 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
925 allocator_traits::construct(*m_alloc, tmp, x);
926 tmp->first_child = nullptr;
927 tmp->last_child = nullptr;
928
929 tmp->parent = position.node;
930 if(position.node->first_child != nullptr)
931 {
932 position.node->first_child->prev_sibling = tmp;
933 }
934 else
935 {
936 position.node->last_child = tmp;
937 }
938 tmp->next_sibling = position.node->first_child;
939 position.node->first_child = tmp;
940 tmp->prev_sibling = nullptr;
941 return tmp;
942}
943
944//--------------------------------------------------------------------------------------//
945
946template <typename T, typename AllocatorT>
947template <typename IterT>
948IterT
950{
951 assert(position.node != head);
952 assert(position.node != feet);
953 assert(position.node);
954
955 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
956 allocator_traits::construct(*m_alloc, tmp, std::forward<T>(x));
957
958 tmp->first_child = nullptr;
959 tmp->last_child = nullptr;
960
961 tmp->parent = position.node;
962 if(position.node->first_child != nullptr)
963 {
964 position.node->first_child->prev_sibling = tmp;
965 }
966 else
967 {
968 position.node->last_child = tmp;
969 }
970 tmp->next_sibling = position.node->first_child;
971 position.node->first_child = tmp;
972 tmp->prev_sibling = nullptr;
973 return tmp;
974}
975
976//--------------------------------------------------------------------------------------//
977
978template <typename T, typename AllocatorT>
979template <typename IterT>
980IterT
981graph<T, AllocatorT>::append_child(IterT position, IterT other)
982{
983 assert(position.node != head);
984 assert(position.node != feet);
985 assert(position.node);
986
987 IterT aargh = append_child(position, value_type{});
988 return move_ontop(aargh, other);
989}
990
991//--------------------------------------------------------------------------------------//
992
993template <typename T, typename AllocatorT>
994template <typename IterT>
995IterT
996graph<T, AllocatorT>::prepend_child(IterT position, IterT other)
997{
998 assert(position.node != head);
999 assert(position.node != feet);
1000 assert(position.node);
1001
1002 IterT aargh = prepend_child(position, value_type{});
1003 return move_ontop(aargh, other);
1004}
1005
1006//--------------------------------------------------------------------------------------//
1007
1008template <typename T, typename AllocatorT>
1009template <typename IterT>
1010IterT
1012 const sibling_iterator& to)
1013{
1014 assert(position.node != head);
1015 assert(position.node != feet);
1016 assert(position.node);
1017
1018 IterT ret = from;
1019
1020 while(from != to)
1021 {
1022 insert_subgraph(position.end(), from);
1023 ++from;
1024 }
1025 return ret;
1026}
1027
1028//--------------------------------------------------------------------------------------//
1029
1030template <typename T, typename AllocatorT>
1031template <typename IterT>
1032IterT
1035{
1036 assert(position.node != head);
1037 assert(position.node != feet);
1038 assert(position.node);
1039
1040 if(from == to)
1041 return from; // should return end of graph?
1042
1043 IterT ret;
1044 do
1045 {
1046 --to;
1047 ret = insert_subgraph(position.begin(), to);
1048 } while(to != from);
1049
1050 return ret;
1051}
1052
1053//--------------------------------------------------------------------------------------//
1054
1055template <typename T, typename AllocatorT>
1058{
1059 assert(head->next_sibling == feet);
1060 return insert(iterator(feet), x);
1061}
1062
1063//--------------------------------------------------------------------------------------//
1064
1065template <typename T, typename AllocatorT>
1068{
1069 assert(head->next_sibling == feet);
1070 return insert(iterator(feet), std::move(x));
1071}
1072
1073//--------------------------------------------------------------------------------------//
1074
1075template <typename T, typename AllocatorT>
1076template <typename IterT>
1077IterT
1078graph<T, AllocatorT>::insert(IterT position, const T& x)
1079{
1080 if(position.node == nullptr)
1081 {
1082 position.node = feet; // Backward compatibility: when calling insert on
1083 // a null node, insert before the feet.
1084 }
1085 assert(position.node != head); // Cannot insert before head.
1086
1087 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1088 allocator_traits::construct(*m_alloc, tmp, x);
1089 tmp->first_child = nullptr;
1090 tmp->last_child = nullptr;
1091
1092 tmp->parent = position.node->parent;
1093 tmp->next_sibling = position.node;
1094 tmp->prev_sibling = position.node->prev_sibling;
1095 position.node->prev_sibling = tmp;
1096
1097 if(tmp->prev_sibling == nullptr)
1098 {
1099 if(tmp->parent) // when inserting nodes at the head, there is no parent
1100 tmp->parent->first_child = tmp;
1101 }
1102 else
1103 tmp->prev_sibling->next_sibling = tmp;
1104 return tmp;
1105}
1106
1107//--------------------------------------------------------------------------------------//
1108
1109template <typename T, typename AllocatorT>
1110template <typename IterT>
1111IterT
1112graph<T, AllocatorT>::insert(IterT position, T&& x)
1113{
1114 if(position.node == nullptr)
1115 {
1116 position.node = feet; // Backward compatibility: when calling insert on
1117 // a null node, insert before the feet.
1118 }
1119 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1120 allocator_traits::construct(*m_alloc, tmp, std::forward<T>(x));
1121
1122 tmp->first_child = nullptr;
1123 tmp->last_child = nullptr;
1124
1125 tmp->parent = position.node->parent;
1126 tmp->next_sibling = position.node;
1127 tmp->prev_sibling = position.node->prev_sibling;
1128 position.node->prev_sibling = tmp;
1129
1130 if(tmp->prev_sibling == nullptr)
1131 {
1132 if(tmp->parent) // when inserting nodes at the head, there is no parent
1133 tmp->parent->first_child = tmp;
1134 }
1135 else
1136 tmp->prev_sibling->next_sibling = tmp;
1137 return tmp;
1138}
1139
1140//--------------------------------------------------------------------------------------//
1141
1142template <typename T, typename AllocatorT>
1145{
1146 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1147 allocator_traits::construct(*m_alloc, tmp, x);
1148 tmp->first_child = nullptr;
1149 tmp->last_child = nullptr;
1150
1151 tmp->next_sibling = position.node;
1152 if(position.node == nullptr)
1153 { // iterator points to end of a subgraph
1154 tmp->parent = position.m_parent;
1155 tmp->prev_sibling = position.range_last();
1156 tmp->parent->last_child = tmp;
1157 }
1158 else
1159 {
1160 tmp->parent = position.node->parent;
1161 tmp->prev_sibling = position.node->prev_sibling;
1162 position.node->prev_sibling = tmp;
1163 }
1164
1165 if(tmp->prev_sibling == nullptr)
1166 {
1167 if(tmp->parent) // when inserting nodes at the head, there is no parent
1168 tmp->parent->first_child = tmp;
1169 }
1170 else
1171 tmp->prev_sibling->next_sibling = tmp;
1172 return tmp;
1173}
1174
1175//--------------------------------------------------------------------------------------//
1176
1177template <typename T, typename AllocatorT>
1178template <typename IterT>
1179IterT
1180graph<T, AllocatorT>::insert_after(IterT position, const T& x)
1181{
1182 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1183 allocator_traits::construct(*m_alloc, tmp, x);
1184 tmp->first_child = nullptr;
1185 tmp->last_child = nullptr;
1186
1187 tmp->parent = position.node->parent;
1188 tmp->prev_sibling = position.node;
1189 tmp->next_sibling = position.node->next_sibling;
1190 position.node->next_sibling = tmp;
1191
1192 if(tmp->next_sibling == nullptr)
1193 {
1194 if(tmp->parent) // when inserting nodes at the head, there is no parent
1195 tmp->parent->last_child = tmp;
1196 }
1197 else
1198 {
1199 tmp->next_sibling->prev_sibling = tmp;
1200 }
1201 return tmp;
1202}
1203
1204//--------------------------------------------------------------------------------------//
1205
1206template <typename T, typename AllocatorT>
1207template <typename IterT>
1208IterT
1210{
1211 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1212 allocator_traits::construct(*m_alloc, tmp, std::forward<T>(x));
1213
1214 tmp->first_child = nullptr;
1215 tmp->last_child = nullptr;
1216
1217 tmp->parent = position.node->parent;
1218 tmp->prev_sibling = position.node;
1219 tmp->next_sibling = position.node->next_sibling;
1220 position.node->next_sibling = tmp;
1221
1222 if(tmp->next_sibling == nullptr)
1223 {
1224 if(tmp->parent) // when inserting nodes at the head, there is no parent
1225 tmp->parent->last_child = tmp;
1226 }
1227 else
1228 {
1229 tmp->next_sibling->prev_sibling = tmp;
1230 }
1231 return tmp;
1232}
1233
1234//--------------------------------------------------------------------------------------//
1235
1236template <typename T, typename AllocatorT>
1237template <typename IterT>
1238IterT
1240{
1241 // insert dummy
1242 IterT it = insert(position, value_type{});
1243 // replace dummy with subgraph
1244 return replace(it, _subgraph);
1245}
1246
1247//--------------------------------------------------------------------------------------//
1248
1249template <typename T, typename AllocatorT>
1250template <typename IterT>
1251IterT
1253 const iterator_base& _subgraph)
1254{
1255 // insert dummy
1256 IterT it = insert_after(position, value_type{});
1257 // replace dummy with subgraph
1258 return replace(it, _subgraph);
1259}
1260
1261//--------------------------------------------------------------------------------------//
1262
1263// template <typename T, typename AllocatorT>
1264// template <typename IterT>
1265// IterT graph<T, AllocatorT>::insert_subgraph(sibling_iterator
1266// position, IterT subgraph)
1267// {
1268// // insert dummy
1269// IterT it(insert(position, value_type{}));
1270// // replace dummy with subgraph
1271// return replace(it, subgraph);
1272// }
1273
1274//--------------------------------------------------------------------------------------//
1275
1276template <typename T, typename AllocatorT>
1277template <typename IterT>
1278IterT
1279graph<T, AllocatorT>::replace(IterT position, const T& x)
1280{
1281 allocator_traits::destroy(*m_alloc, position.node);
1282 allocator_traits::construct(*m_alloc, position.node, x);
1283 return position;
1284}
1285
1286//--------------------------------------------------------------------------------------//
1287
1288template <typename T, typename AllocatorT>
1289template <typename IterT>
1290IterT
1291graph<T, AllocatorT>::replace(IterT position, T&& x)
1292{
1293 allocator_traits::destroy(*m_alloc, position.node);
1294 allocator_traits::construct(*m_alloc, position.node, std::forward<T>(x));
1295 return position;
1296}
1297
1298//--------------------------------------------------------------------------------------//
1299
1300template <typename T, typename AllocatorT>
1301template <typename IterT>
1302IterT
1304{
1305 assert(position.node != head);
1306 graph_node* current_from = from.node;
1307 graph_node* start_from = from.node;
1308 graph_node* current_to = position.node;
1309
1310 // replace the node at position with head of the replacement graph at from
1311 // std::cout << "warning!" << position.node << std::endl;
1312 erase_children(position);
1313 // std::cout << "no warning!" << std::endl;
1314 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1315 allocator_traits::construct(*m_alloc, tmp, (*from));
1316 tmp->first_child = nullptr;
1317 tmp->last_child = nullptr;
1318 if(current_to->prev_sibling == nullptr)
1319 {
1320 if(current_to->parent != nullptr)
1321 current_to->parent->first_child = tmp;
1322 }
1323 else
1324 {
1325 current_to->prev_sibling->next_sibling = tmp;
1326 }
1327 tmp->prev_sibling = current_to->prev_sibling;
1328 if(current_to->next_sibling == nullptr)
1329 {
1330 if(current_to->parent != nullptr)
1331 current_to->parent->last_child = tmp;
1332 }
1333 else
1334 {
1335 current_to->next_sibling->prev_sibling = tmp;
1336 }
1337 tmp->next_sibling = current_to->next_sibling;
1338 tmp->parent = current_to->parent;
1339 allocator_traits::destroy(*m_alloc, current_to);
1340 allocator_traits::deallocate(*m_alloc, current_to, 1);
1341 current_to = tmp;
1342
1343 // only at this stage can we fix 'last'
1344 graph_node* last = from.node->next_sibling;
1345
1346 pre_order_iterator toit = tmp;
1347 // copy all children
1348 do
1349 {
1350 assert(current_from != nullptr);
1351 if(current_from->first_child != nullptr)
1352 {
1353 current_from = current_from->first_child;
1354 toit = append_child(toit, current_from->data);
1355 }
1356 else
1357 {
1358 while(current_from->next_sibling == nullptr && current_from != start_from)
1359 {
1360 current_from = current_from->parent;
1361 toit = parent(toit);
1362 assert(current_from != nullptr);
1363 }
1364 current_from = current_from->next_sibling;
1365 if(current_from != last && current_from)
1366 {
1367 toit = append_child(parent(toit), current_from->data);
1368 }
1369 }
1370 } while(current_from != last && current_from);
1371
1372 return current_to;
1373}
1374
1375//--------------------------------------------------------------------------------------//
1376
1377template <typename T, typename AllocatorT>
1380 const sibling_iterator& orig_end,
1381 sibling_iterator new_begin, const sibling_iterator& new_end)
1382{
1383 graph_node* orig_first = orig_begin.node;
1384 graph_node* new_first = new_begin.node;
1385 graph_node* orig_last = orig_first;
1386 while((++orig_begin) != orig_end)
1387 orig_last = orig_last->next_sibling;
1388 graph_node* new_last = new_first;
1389 while((++new_begin) != new_end)
1390 new_last = new_last->next_sibling;
1391
1392 // insert all siblings in new_first..new_last before orig_first
1393 bool first = true;
1395 while(true)
1396 {
1398 pre_order_iterator(new_first));
1399 if(first)
1400 {
1401 ret = tt;
1402 first = false;
1403 }
1404 if(new_first == new_last)
1405 break;
1406 new_first = new_first->next_sibling;
1407 }
1408
1409 // erase old range of siblings
1410 bool last = false;
1411 graph_node* next = orig_first;
1412 while(true)
1413 {
1414 if(next == orig_last)
1415 last = true;
1416 next = next->next_sibling;
1417 erase((pre_order_iterator) orig_first);
1418 if(last)
1419 break;
1420 orig_first = next;
1421 }
1422 return ret;
1423}
1424
1425//--------------------------------------------------------------------------------------//
1426
1427template <typename T, typename AllocatorT>
1428template <typename IterT>
1429IterT
1431{
1432 if(position.node->first_child == nullptr)
1433 return position;
1434
1435 graph_node* tmp = position.node->first_child;
1436 while(tmp)
1437 {
1438 tmp->parent = position.node->parent;
1439 tmp = tmp->next_sibling;
1440 }
1441 if(position.node->next_sibling)
1442 {
1443 position.node->last_child->next_sibling = position.node->next_sibling;
1444 position.node->next_sibling->prev_sibling = position.node->last_child;
1445 }
1446 else
1447 {
1448 position.node->parent->last_child = position.node->last_child;
1449 }
1450 position.node->next_sibling = position.node->first_child;
1451 position.node->next_sibling->prev_sibling = position.node;
1452 position.node->first_child = nullptr;
1453 position.node->last_child = nullptr;
1454
1455 return position;
1456}
1457
1458//--------------------------------------------------------------------------------------//
1459
1460template <typename T, typename AllocatorT>
1461template <typename IterT>
1462IterT
1464 const sibling_iterator& _end)
1465{
1466 graph_node* first = _begin.node;
1467 graph_node* last = first;
1468
1469 assert(first != position.node);
1470
1471 if(_begin == _end)
1472 return _begin;
1473 // determine last node
1474 while((++_begin) != _end)
1475 {
1476 last = last->next_sibling;
1477 }
1478 // move subgraph
1479 if(first->prev_sibling == nullptr)
1480 {
1481 first->parent->first_child = last->next_sibling;
1482 }
1483 else
1484 {
1485 first->prev_sibling->next_sibling = last->next_sibling;
1486 }
1487 if(last->next_sibling == nullptr)
1488 {
1489 last->parent->last_child = first->prev_sibling;
1490 }
1491 else
1492 {
1493 last->next_sibling->prev_sibling = first->prev_sibling;
1494 }
1495 if(position.node->first_child == nullptr)
1496 {
1497 position.node->first_child = first;
1498 position.node->last_child = last;
1499 first->prev_sibling = nullptr;
1500 }
1501 else
1502 {
1503 position.node->last_child->next_sibling = first;
1504 first->prev_sibling = position.node->last_child;
1505 position.node->last_child = last;
1506 }
1507 last->next_sibling = nullptr;
1508
1509 graph_node* pos = first;
1510 for(;;)
1511 {
1512 pos->parent = position.node;
1513 if(pos == last)
1514 break;
1515 pos = pos->next_sibling;
1516 }
1517
1518 return first;
1519}
1520
1521//--------------------------------------------------------------------------------------//
1522
1523template <typename T, typename AllocatorT>
1524template <typename IterT>
1525IterT
1526graph<T, AllocatorT>::reparent(IterT position, IterT from)
1527{
1528 if(from.node->first_child == nullptr)
1529 return position;
1530 return reparent(position, from.node->first_child, end(from));
1531}
1532
1533//--------------------------------------------------------------------------------------//
1534
1535template <typename T, typename AllocatorT>
1536template <typename IterT>
1537IterT
1538graph<T, AllocatorT>::wrap(IterT position, const T& x)
1539{
1540 assert(position.node != nullptr);
1541 sibling_iterator fr = position;
1542 sibling_iterator to = position;
1543 ++to;
1544 IterT ret = insert(position, x);
1545 reparent(ret, fr, to);
1546 return ret;
1547}
1548
1549//--------------------------------------------------------------------------------------//
1550
1551template <typename T, typename AllocatorT>
1552template <typename IterT>
1553IterT
1554graph<T, AllocatorT>::wrap(IterT from, IterT to, const T& x)
1555{
1556 assert(from.node != nullptr);
1557 IterT ret = insert(from, x);
1558 reparent(ret, from, to);
1559 return ret;
1560}
1561
1562//--------------------------------------------------------------------------------------//
1563
1564template <typename T, typename AllocatorT>
1565template <typename IterT>
1566IterT
1567graph<T, AllocatorT>::move_after(IterT target, IterT source)
1568{
1569 graph_node* dst = target.node;
1570 graph_node* src = source.node;
1571 assert(dst);
1572 assert(src);
1573
1574 if(dst == src)
1575 return source;
1576 if(dst->next_sibling)
1577 {
1578 if(dst->next_sibling == src) // already in the right spot
1579 return source;
1580 }
1581
1582 // take src out of the graph
1583 if(src->prev_sibling != nullptr)
1584 {
1585 src->prev_sibling->next_sibling = src->next_sibling;
1586 }
1587 else
1588 {
1589 src->parent->first_child = src->next_sibling;
1590 }
1591 if(src->next_sibling != nullptr)
1592 {
1593 src->next_sibling->prev_sibling = src->prev_sibling;
1594 }
1595 else
1596 {
1597 src->parent->last_child = src->prev_sibling;
1598 }
1599
1600 // connect it to the new point
1601 if(dst->next_sibling != nullptr)
1602 {
1603 dst->next_sibling->prev_sibling = src;
1604 }
1605 else
1606 {
1607 dst->parent->last_child = src;
1608 }
1609 src->next_sibling = dst->next_sibling;
1610 dst->next_sibling = src;
1611 src->prev_sibling = dst;
1612 src->parent = dst->parent;
1613 return src;
1614}
1615
1616//--------------------------------------------------------------------------------------//
1617
1618template <typename T, typename AllocatorT>
1619template <typename IterT>
1620IterT
1621graph<T, AllocatorT>::move_before(IterT target, IterT source)
1622{
1623 graph_node* dst = target.node;
1624 graph_node* src = source.node;
1625 assert(dst);
1626 assert(src);
1627
1628 if(dst == src)
1629 return source;
1630 if(dst->prev_sibling)
1631 {
1632 if(dst->prev_sibling == src) // already in the right spot
1633 return source;
1634 }
1635
1636 // take src out of the graph
1637 if(src->prev_sibling != nullptr)
1638 {
1639 src->prev_sibling->next_sibling = src->next_sibling;
1640 }
1641 else
1642 {
1643 src->parent->first_child = src->next_sibling;
1644 }
1645 if(src->next_sibling != nullptr)
1646 {
1647 src->next_sibling->prev_sibling = src->prev_sibling;
1648 }
1649 else
1650 {
1651 src->parent->last_child = src->prev_sibling;
1652 }
1653
1654 // connect it to the new point
1655 if(dst->prev_sibling != nullptr)
1656 {
1657 dst->prev_sibling->next_sibling = src;
1658 }
1659 else
1660 {
1661 dst->parent->first_child = src;
1662 }
1663 src->prev_sibling = dst->prev_sibling;
1664 dst->prev_sibling = src;
1665 src->next_sibling = dst;
1666 src->parent = dst->parent;
1667 return src;
1668}
1669
1670//--------------------------------------------------------------------------------------//
1671
1672template <typename T, typename AllocatorT>
1673template <typename IterT>
1674IterT
1675graph<T, AllocatorT>::move_ontop(IterT target, IterT source)
1676{
1677 graph_node* dst = target.node;
1678 graph_node* src = source.node;
1679 assert(dst);
1680 assert(src);
1681
1682 if(dst == src)
1683 return source;
1684
1685 // if(dst==src->prev_sibling) {
1686 //
1687 // }
1688
1689 // remember connection points
1690 graph_node* b_prev_sibling = dst->prev_sibling;
1691 graph_node* b_next_sibling = dst->next_sibling;
1692 graph_node* b_parent = dst->parent;
1693
1694 // remove target
1695 erase(target);
1696
1697 // take src out of the graph
1698 if(src->prev_sibling != nullptr)
1699 {
1700 src->prev_sibling->next_sibling = src->next_sibling;
1701 }
1702 else
1703 {
1704 src->parent->first_child = src->next_sibling;
1705 }
1706 if(src->next_sibling != nullptr)
1707 {
1708 src->next_sibling->prev_sibling = src->prev_sibling;
1709 }
1710 else
1711 {
1712 src->parent->last_child = src->prev_sibling;
1713 }
1714
1715 // connect it to the new point
1716 if(b_prev_sibling != nullptr)
1717 {
1718 b_prev_sibling->next_sibling = src;
1719 }
1720 else
1721 {
1722 b_parent->first_child = src;
1723 }
1724 if(b_next_sibling != nullptr)
1725 {
1726 b_next_sibling->prev_sibling = src;
1727 }
1728 else
1729 {
1730 b_parent->last_child = src;
1731 }
1732 src->prev_sibling = b_prev_sibling;
1733 src->next_sibling = b_next_sibling;
1734 src->parent = b_parent;
1735 return src;
1736}
1737
1738//--------------------------------------------------------------------------------------//
1739
1740template <typename T, typename AllocatorT>
1743{
1744 graph ret;
1745
1746 // Move source node into the 'ret' graph.
1747 ret.head->next_sibling = source.node;
1748 ret.feet->prev_sibling = source.node;
1749 source.node->parent = nullptr;
1750
1751 // Close the links in the current graph.
1752 if(source.node->prev_sibling != nullptr)
1753 source.node->prev_sibling->next_sibling = source.node->next_sibling;
1754
1755 if(source.node->next_sibling != nullptr)
1756 source.node->next_sibling->prev_sibling = source.node->prev_sibling;
1757
1758 // Fix source prev/next links.
1759 source.node->prev_sibling = ret.head;
1760 source.node->next_sibling = ret.feet;
1761
1762 return ret; // A good compiler will move this, not copy.
1763}
1764
1765//--------------------------------------------------------------------------------------//
1766
1767template <typename T, typename AllocatorT>
1768template <typename IterT>
1769IterT
1771{
1772 if(other.head->next_sibling == other.feet)
1773 return loc; // other graph is empty
1774
1775 graph_node* other_first_head = other.head->next_sibling;
1776 graph_node* other_last_head = other.feet->prev_sibling;
1777
1778 sibling_iterator prev(loc);
1779 --prev;
1780
1781 prev.node->next_sibling = other_first_head;
1782 loc.node->prev_sibling = other_last_head;
1783 other_first_head->prev_sibling = prev.node;
1784 other_last_head->next_sibling = loc.node;
1785
1786 // Adjust parent pointers.
1787 graph_node* walk = other_first_head;
1788 while(true)
1789 {
1790 walk->parent = loc.node->parent;
1791 if(walk == other_last_head)
1792 break;
1793 walk = walk->next_sibling;
1794 }
1795
1796 // Close other graph.
1797 other.head->next_sibling = other.feet;
1798 other.feet->prev_sibling = other.head;
1799
1800 return other_first_head;
1801}
1802
1803//--------------------------------------------------------------------------------------//
1804
1805template <typename T, typename AllocatorT>
1806template <typename IterT>
1807IterT
1809{
1810 if(other.head->next_sibling == other.feet)
1811 return loc; // other graph is empty
1812
1813 graph_node* other_first_head = other.head->next_sibling;
1814 graph_node* other_last_head = other.feet->prev_sibling;
1815
1816 if(n == 0)
1817 {
1818 if(loc.node->first_child == nullptr)
1819 {
1820 loc.node->first_child = other_first_head;
1821 loc.node->last_child = other_last_head;
1822 other_last_head->next_sibling = nullptr;
1823 other_first_head->prev_sibling = nullptr;
1824 }
1825 else
1826 {
1827 loc.node->first_child->prev_sibling = other_last_head;
1828 other_last_head->next_sibling = loc.node->first_child;
1829 loc.node->first_child = other_first_head;
1830 other_first_head->prev_sibling = nullptr;
1831 }
1832 }
1833 else
1834 {
1835 --n;
1836 graph_node* walk = loc.node->first_child;
1837 while(true)
1838 {
1839 if(walk == nullptr)
1840 {
1841 throw std::range_error(
1842 "graph: move_in_as_nth_child position out of range");
1843 }
1844 if(n == 0)
1845 break;
1846 --n;
1847 walk = walk->next_sibling;
1848 }
1849 if(walk->next_sibling == nullptr)
1850 {
1851 loc.node->last_child = other_last_head;
1852 }
1853 else
1854 {
1855 walk->next_sibling->prev_sibling = other_last_head;
1856 }
1857 other_last_head->next_sibling = walk->next_sibling;
1858 walk->next_sibling = other_first_head;
1859 other_first_head->prev_sibling = walk;
1860 }
1861
1862 // Adjust parent pointers.
1863 graph_node* walk = other_first_head;
1864 while(true)
1865 {
1866 walk->parent = loc.node;
1867 if(walk == other_last_head)
1868 break;
1869 walk = walk->next_sibling;
1870 }
1871
1872 // Close other graph.
1873 other.head->next_sibling = other.feet;
1874 other.feet->prev_sibling = other.head;
1875
1876 return other_first_head;
1877}
1878
1879//--------------------------------------------------------------------------------------//
1880
1881template <typename T, typename AllocatorT>
1882void
1884 sibling_iterator from1, const sibling_iterator& from2,
1885 bool duplicate_leaves, bool first)
1886{
1887 while(from1 != from2)
1888 {
1889 sibling_iterator fnd;
1890 auto nsiblings = number_of_siblings(to1);
1891 decltype(nsiblings) count = nullptr;
1892 for(sibling_iterator itr = to1; itr != to2; ++itr, ++count)
1893 {
1894 if(itr && from1 && *itr == *from1)
1895 {
1896 fnd = itr;
1897 break;
1898 }
1899 if(count > nsiblings)
1900 {
1901 fnd = to2;
1902 break;
1903 }
1904 }
1905 // auto fnd = std::find(to1, to2, *from1);
1906 if(fnd != to2) // element found
1907 {
1908 if(from1.begin() == from1.end()) // full depth reached
1909 {
1910 if(duplicate_leaves)
1911 append_child(parent(to1), (*from1));
1912 }
1913 else // descend further
1914 {
1915 if(!first)
1916 *fnd += *from1;
1917 if(from1 != from2)
1918 {
1919 merge(fnd.begin(), fnd.end(), from1.begin(), from1.end(),
1920 duplicate_leaves);
1921 }
1922 }
1923 }
1924 else
1925 { // element missing
1926 insert_subgraph(to2, from1);
1927 }
1928 do
1929 {
1930 ++from1;
1931 } while(!from1 && from1 != from2);
1932 }
1933}
1934
1935//--------------------------------------------------------------------------------------//
1936
1937template <typename T, typename AllocatorT>
1938template <typename ComparePred, typename ReducePred>
1939void
1941 std::set<sibling_iterator>& _erase, ComparePred&& _compare,
1942 ReducePred&& _reduce)
1943{
1944 if(!is_valid(lhs))
1945 return;
1946
1947 for(pre_order_iterator litr = lhs; litr != feet; ++litr)
1948 {
1949 if(!litr)
1950 continue;
1951
1952 uint32_t nsiblings = number_of_siblings(litr);
1953 if(nsiblings < 2)
1954 continue;
1955
1956 uint32_t idx = index(litr);
1957 for(uint32_t i = 0; i < nsiblings; ++i)
1958 {
1959 if(i == idx)
1960 continue;
1961
1962 sibling_iterator ritr = sibling(litr, i);
1963
1964 if(!ritr)
1965 continue;
1966
1967 // skip if same iterator
1968 if(litr.node == ritr.node)
1969 continue;
1970
1971 if(_erase.find(ritr) != _erase.end())
1972 continue;
1973
1974 if(_compare(litr, ritr))
1975 {
1976 pre_order_iterator pritr(ritr);
1977 // printf("\n");
1978 // pre_order_iterator critr = pritr.begin();
1979 // auto aitr = append_child(litr, critr);
1980 auto aitr = insert_subgraph_after(litr, pritr);
1981 reduce(aitr.begin(), feet, _erase, _compare, _reduce);
1982 // insert_subgraph_after(litr, pritr);
1983 _erase.insert(ritr);
1984 reduce(litr.begin(), feet, _erase, _compare, _reduce);
1985 _reduce(litr, ritr);
1986 // this->erase(ritr);
1987
1988 // break;
1989 }
1990 }
1991
1992 for(auto& itr : _erase)
1993 this->erase(itr);
1994
1995 if(_erase.size() > 0)
1996 {
1997 _erase.clear();
1998 break;
1999 }
2000 // reduce(litr.begin(), feet, _erase, _compare, _reduce);
2001 }
2002}
2003
2004//--------------------------------------------------------------------------------------//
2005
2006template <typename T, typename AllocatorT>
2007template <typename IterT>
2008bool
2009graph<T, AllocatorT>::equal(const IterT& one_, const IterT& two,
2010 const IterT& three_) const
2011{
2012 std::equal_to<T> comp;
2013 return equal(one_, two, three_, comp);
2014}
2015
2016//--------------------------------------------------------------------------------------//
2017
2018template <typename T, typename AllocatorT>
2019template <typename IterT>
2020bool
2021graph<T, AllocatorT>::equal_subgraph(const IterT& one_, const IterT& two_) const
2022{
2023 std::equal_to<T> comp;
2024 return equal_subgraph(one_, two_, comp);
2025}
2026
2027//--------------------------------------------------------------------------------------//
2028
2029template <typename T, typename AllocatorT>
2030template <typename IterT, typename BinaryPredicate>
2031bool
2032graph<T, AllocatorT>::equal(const IterT& one_, const IterT& two, const IterT& three_,
2033 BinaryPredicate fun) const
2034{
2035 pre_order_iterator one(one_);
2036 pre_order_iterator three(three_);
2037
2038 // if(one==two && is_valid(three) && three.number_of_children()!=0)
2039 // return false;
2040 while(one != two && is_valid(three))
2041 {
2042 if(!fun(*one, *three))
2043 return false;
2044 if(one.number_of_children() != three.number_of_children())
2045 return false;
2046 ++one;
2047 ++three;
2048 }
2049 return true;
2050}
2051
2052//--------------------------------------------------------------------------------------//
2053
2054template <typename T, typename AllocatorT>
2055template <typename IterT, typename BinaryPredicate>
2056bool
2057graph<T, AllocatorT>::equal_subgraph(const IterT& one_, const IterT& two_,
2058 BinaryPredicate fun) const
2059{
2060 pre_order_iterator one(one_);
2061 pre_order_iterator two(two_);
2062
2063 if(!fun(*one, *two))
2064 return false;
2065 if(number_of_children(one) != number_of_children(two))
2066 return false;
2067 return equal(begin(one), end(one), begin(two), fun);
2068}
2069
2070//--------------------------------------------------------------------------------------//
2071
2072template <typename T, typename AllocatorT>
2073bool
2075{
2077 pre_order_iterator eit = end();
2078 return (it == eit);
2079}
2080
2081//--------------------------------------------------------------------------------------//
2082
2083template <typename T, typename AllocatorT>
2084int
2086{
2087 graph_node* pos = it.node;
2088 assert(pos != nullptr);
2089 int ret = 0;
2090 while(pos->parent != nullptr)
2091 {
2092 pos = pos->parent;
2093 ++ret;
2094 }
2095 return ret;
2096}
2097
2098//--------------------------------------------------------------------------------------//
2099
2100template <typename T, typename AllocatorT>
2101int
2103{
2104 graph_node* pos = it.node;
2105 assert(pos != nullptr);
2106 int ret = 0;
2107 while(pos->parent != nullptr && pos != root.node)
2108 {
2109 pos = pos->parent;
2110 ++ret;
2111 }
2112 return ret;
2113}
2114
2115//--------------------------------------------------------------------------------------//
2116
2117template <typename T, typename AllocatorT>
2118int
2120{
2121 int maxd = -1;
2122 for(graph_node* it = head->next_sibling; it != feet; it = it->next_sibling)
2123 maxd = std::max(maxd, max_depth(it));
2124
2125 return maxd;
2126}
2127
2128//--------------------------------------------------------------------------------------//
2129
2130template <typename T, typename AllocatorT>
2131int
2133{
2134 graph_node* tmp = pos.node;
2135
2136 if(tmp == nullptr || tmp == head || tmp == feet)
2137 return -1;
2138
2139 int curdepth = 0;
2140 int maxdepth = 0;
2141 while(true)
2142 { // try to walk the bottom of the graph
2143 while(tmp->first_child == nullptr)
2144 {
2145 if(tmp == pos.node)
2146 return maxdepth;
2147 if(tmp->next_sibling == nullptr)
2148 {
2149 // try to walk up and then right again
2150 do
2151 {
2152 tmp = tmp->parent;
2153 if(tmp == nullptr)
2154 return maxdepth;
2155 --curdepth;
2156 } while(tmp->next_sibling == nullptr);
2157 }
2158 if(tmp == pos.node)
2159 return maxdepth;
2160 tmp = tmp->next_sibling;
2161 }
2162 tmp = tmp->first_child;
2163 ++curdepth;
2164 maxdepth = std::max(curdepth, maxdepth);
2165 }
2166}
2167
2168//--------------------------------------------------------------------------------------//
2169
2170template <typename T, typename AllocatorT>
2171unsigned int
2173{
2175 if(pos == nullptr)
2176 return 0;
2177
2178 unsigned int ret = 1;
2179 while((pos = pos->next_sibling))
2180 ++ret;
2181 return ret;
2182}
2183
2184//--------------------------------------------------------------------------------------//
2185
2186template <typename T, typename AllocatorT>
2187unsigned int
2189{
2190 graph_node* pos = it.node;
2191 unsigned int ret = 0;
2192 // count forward
2193 while(pos->next_sibling && pos->next_sibling != head && pos->next_sibling != feet)
2194 {
2195 ++ret;
2196 pos = pos->next_sibling;
2197 }
2198 // count backward
2199 pos = it.node;
2200 while(pos->prev_sibling && pos->prev_sibling != head && pos->prev_sibling != feet)
2201 {
2202 ++ret;
2203 pos = pos->prev_sibling;
2204 }
2205
2206 return ret;
2207}
2208
2209//--------------------------------------------------------------------------------------//
2210
2211template <typename T, typename AllocatorT>
2212void
2214{
2215 graph_node* nxt = it.node->next_sibling;
2216 if(nxt)
2217 {
2218 if(it.node->prev_sibling)
2219 {
2220 it.node->prev_sibling->next_sibling = nxt;
2221 }
2222 else
2223 {
2224 it.node->parent->first_child = nxt;
2225 }
2226 nxt->prev_sibling = it.node->prev_sibling;
2227 graph_node* nxtnxt = nxt->next_sibling;
2228 if(nxtnxt)
2229 {
2230 nxtnxt->prev_sibling = it.node;
2231 }
2232 else
2233 {
2234 it.node->parent->last_child = it.node;
2235 }
2236 nxt->next_sibling = it.node;
2237 it.node->prev_sibling = nxt;
2238 it.node->next_sibling = nxtnxt;
2239 }
2240}
2241
2242//--------------------------------------------------------------------------------------//
2243
2244template <typename T, typename AllocatorT>
2245void
2247{
2248 // if one and two are adjacent siblings, use the sibling swap
2249 if(one.node->next_sibling == two.node)
2250 {
2251 swap(one);
2252 }
2253 else if(two.node->next_sibling == one.node)
2254 {
2255 swap(two);
2256 }
2257 else
2258 {
2259 graph_node* nxt1 = one.node->next_sibling;
2260 graph_node* nxt2 = two.node->next_sibling;
2261 graph_node* pre1 = one.node->prev_sibling;
2262 graph_node* pre2 = two.node->prev_sibling;
2263 graph_node* par1 = one.node->parent;
2264 graph_node* par2 = two.node->parent;
2265
2266 // reconnect
2267 one.node->parent = par2;
2268 one.node->next_sibling = nxt2;
2269 if(nxt2)
2270 {
2271 nxt2->prev_sibling = one.node;
2272 }
2273 else
2274 {
2275 par2->last_child = one.node;
2276 }
2277 one.node->prev_sibling = pre2;
2278 if(pre2)
2279 {
2280 pre2->next_sibling = one.node;
2281 }
2282 else
2283 {
2284 par2->first_child = one.node;
2285 }
2286
2287 two.node->parent = par1;
2288 two.node->next_sibling = nxt1;
2289 if(nxt1)
2290 {
2291 nxt1->prev_sibling = two.node;
2292 }
2293 else
2294 {
2295 par1->last_child = two.node;
2296 }
2297 two.node->prev_sibling = pre1;
2298 if(pre1)
2299 {
2300 pre1->next_sibling = two.node;
2301 }
2302 else
2303 {
2304 par1->first_child = two.node;
2305 }
2306 }
2307}
2308
2309//--------------------------------------------------------------------------------------//
2310
2311template <typename T, typename AllocatorT>
2312bool
2314{
2315 if(it.node == nullptr || it.node == feet || it.node == head)
2316 {
2317 return false;
2318 }
2319 {
2320 return true;
2321 }
2322}
2323
2324//--------------------------------------------------------------------------------------//
2325
2326template <typename T, typename AllocatorT>
2327bool
2329{
2330 if(it.node->parent == nullptr)
2331 return true;
2332 return false;
2333}
2334
2335//--------------------------------------------------------------------------------------//
2336
2337template <typename T, typename AllocatorT>
2338inline unsigned int
2340{
2341 graph_node* tmp = it.node;
2342 if(!tmp)
2343 return static_cast<unsigned int>(-1);
2344
2345 if(tmp->parent != nullptr)
2346 {
2347 tmp = tmp->parent->first_child;
2348 }
2349 else
2350 {
2351 while(tmp->prev_sibling != nullptr)
2352 tmp = tmp->prev_sibling;
2353 }
2354
2355 unsigned int ret = 0;
2356 while(tmp != it.node)
2357 {
2358 ++ret;
2359 tmp = tmp->next_sibling;
2360 }
2361
2362 return ret;
2363}
2364
2365//--------------------------------------------------------------------------------------//
2366
2367template <typename T, typename AllocatorT>
2369graph<T, AllocatorT>::sibling(const iterator_base& it, unsigned int num) const
2370{
2371 graph_node* tmp = it.node;
2372 if(!tmp)
2373 return sibling_iterator(nullptr);
2374
2375 if(tmp->parent != nullptr)
2376 {
2377 tmp = tmp->parent->first_child;
2378 }
2379 else
2380 {
2381 while(tmp->prev_sibling != nullptr)
2382 tmp = tmp->prev_sibling;
2383 }
2384
2385 while((num--) != 0u)
2386 {
2387 assert(tmp != nullptr);
2388 tmp = tmp->next_sibling;
2389 }
2390 return tmp;
2391}
2392
2393//--------------------------------------------------------------------------------------//
2394
2395template <typename T, typename AllocatorT>
2397graph<T, AllocatorT>::child(const iterator_base& it, unsigned int num)
2398{
2399 graph_node* tmp = it.node->first_child;
2400 while((num--) != 0u)
2401 {
2402 assert(tmp != nullptr);
2403 tmp = tmp->next_sibling;
2404 }
2405 return tmp;
2406}
2407
2408//--------------------------------------------------------------------------------------//
2409// Iterator base
2410
2411template <typename T, typename AllocatorT>
2413: node(nullptr)
2414
2415{}
2416
2417//--------------------------------------------------------------------------------------//
2418
2419template <typename T, typename AllocatorT>
2421: node(tn)
2422
2423{}
2424
2425//--------------------------------------------------------------------------------------//
2426
2427template <typename T, typename AllocatorT>
2429{
2430 return node->data;
2431}
2432
2433//--------------------------------------------------------------------------------------//
2434
2435template <typename T, typename AllocatorT>
2437{
2438 return &(node->data);
2439}
2440
2441//--------------------------------------------------------------------------------------//
2442
2443template <typename T, typename AllocatorT>
2444bool
2446 const pre_order_iterator& other) const
2447{
2448 if(other.node != this->node)
2449 {
2450 return true;
2451 }
2452 {
2453 return false;
2454 }
2455}
2456
2457//--------------------------------------------------------------------------------------//
2458
2459template <typename T, typename AllocatorT>
2460bool
2462 const pre_order_iterator& other) const
2463{
2464 if(other.node == this->node)
2465 {
2466 return true;
2467 }
2468 {
2469 return false;
2470 }
2471}
2472
2473//--------------------------------------------------------------------------------------//
2474
2475template <typename T, typename AllocatorT>
2476bool
2478{
2479 if(other.node != this->node)
2480 {
2481 return true;
2482 }
2483 {
2484 return false;
2485 }
2486}
2487
2488//--------------------------------------------------------------------------------------//
2489
2490template <typename T, typename AllocatorT>
2491bool
2493{
2494 if(other.node == this->node)
2495 {
2496 return true;
2497 }
2498 {
2499 return false;
2500 }
2501}
2502
2503//--------------------------------------------------------------------------------------//
2504
2505template <typename T, typename AllocatorT>
2508{
2509 if(node->first_child == nullptr)
2510 return end();
2511
2512 sibling_iterator ret(node->first_child);
2513 ret.m_parent = this->node;
2514 return ret;
2515}
2516
2517//--------------------------------------------------------------------------------------//
2518
2519template <typename T, typename AllocatorT>
2522{
2523 sibling_iterator ret(nullptr);
2524 ret.m_parent = node;
2525 return ret;
2526}
2527
2528//--------------------------------------------------------------------------------------//
2529
2530template <typename T, typename AllocatorT>
2531void
2533{
2534 m_skip_current_children = true;
2535}
2536
2537//--------------------------------------------------------------------------------------//
2538
2539template <typename T, typename AllocatorT>
2540void
2542{
2543 m_skip_current_children = skip;
2544}
2545
2546//--------------------------------------------------------------------------------------//
2547
2548template <typename T, typename AllocatorT>
2549unsigned int
2551{
2552 graph_node* pos = node->first_child;
2553 if(pos == nullptr)
2554 return 0;
2555
2556 unsigned int ret = 1;
2557 while(pos != node->last_child)
2558 {
2559 ++ret;
2560 pos = pos->next_sibling;
2561 }
2562 return ret;
2563}
2564
2565//--------------------------------------------------------------------------------------//
2566// Pre-order iterator
2567
2568template <typename T, typename AllocatorT>
2570: iterator_base(nullptr)
2571{}
2572
2573//--------------------------------------------------------------------------------------//
2574
2575template <typename T, typename AllocatorT>
2577: iterator_base(tn)
2578{}
2579
2580//--------------------------------------------------------------------------------------//
2581
2582template <typename T, typename AllocatorT>
2584: iterator_base(other.node)
2585{}
2586
2587//--------------------------------------------------------------------------------------//
2588
2589template <typename T, typename AllocatorT>
2591 const sibling_iterator& other)
2592: iterator_base(other.node)
2593{
2594 if(this->node == nullptr)
2595 {
2596 if(other.range_last() != nullptr)
2597 {
2598 this->node = other.range_last();
2599 }
2600 else
2601 {
2602 this->node = other.m_parent;
2603 }
2604 this->skip_children();
2605 ++(*this);
2606 }
2607}
2608
2609//--------------------------------------------------------------------------------------//
2610
2611template <typename T, typename AllocatorT>
2614{
2615 assert(this->node != nullptr);
2616 if(!this->m_skip_current_children && this->node->first_child != nullptr)
2617 {
2618 this->node = this->node->first_child;
2619 }
2620 else
2621 {
2622 this->m_skip_current_children = false;
2623 while(this->node->next_sibling == nullptr)
2624 {
2625 this->node = this->node->parent;
2626 if(this->node == nullptr)
2627 return *this;
2628 }
2629 this->node = this->node->next_sibling;
2630 }
2631 return *this;
2632}
2633
2634//--------------------------------------------------------------------------------------//
2635
2636template <typename T, typename AllocatorT>
2639{
2640 assert(this->node != nullptr);
2641 if(this->node->prev_sibling)
2642 {
2643 this->node = this->node->prev_sibling;
2644 while(this->node->last_child)
2645 this->node = this->node->last_child;
2646 }
2647 else
2648 {
2649 this->node = this->node->parent;
2650 if(this->node == nullptr)
2651 return *this;
2652 }
2653 return *this;
2654}
2655
2656//--------------------------------------------------------------------------------------//
2657
2658template <typename T, typename AllocatorT>
2661{
2662 pre_order_iterator copy = *this;
2663 ++(*this);
2664 return copy;
2665}
2666
2667//--------------------------------------------------------------------------------------//
2668
2669template <typename T, typename AllocatorT>
2672{
2673 pre_order_iterator copy = *this;
2674 --(*this);
2675 return copy;
2676}
2677
2678//--------------------------------------------------------------------------------------//
2679
2680template <typename T, typename AllocatorT>
2683{
2684 while(num > 0)
2685 {
2686 ++(*this);
2687 --num;
2688 }
2689 return (*this);
2690}
2691
2692//--------------------------------------------------------------------------------------//
2693
2694template <typename T, typename AllocatorT>
2697{
2698 while(num > 0)
2699 {
2700 --(*this);
2701 --num;
2702 }
2703 return (*this);
2704}
2705
2706//--------------------------------------------------------------------------------------//
2707
2708template <typename T, typename AllocatorT>
2711{
2712 auto itr = *this;
2713 while(num > 0)
2714 {
2715 ++itr;
2716 --num;
2717 }
2718 return itr;
2719}
2720
2721//--------------------------------------------------------------------------------------//
2722// Sibling iterator
2723template <typename T, typename AllocatorT>
2725: iterator_base()
2726{
2727 m_set_parent();
2728}
2729
2730//--------------------------------------------------------------------------------------//
2731
2732template <typename T, typename AllocatorT>
2734: iterator_base(tn)
2735{
2736 m_set_parent();
2737}
2738
2739//--------------------------------------------------------------------------------------//
2740
2741template <typename T, typename AllocatorT>
2743: iterator_base(other.node)
2744{
2745 m_set_parent();
2746}
2747
2748//--------------------------------------------------------------------------------------//
2749
2750template <typename T, typename AllocatorT>
2751void
2753{
2754 m_parent = nullptr;
2755 if(this->node == nullptr)
2756 return;
2757 if(this->node->parent != nullptr)
2758 m_parent = this->node->parent;
2759}
2760
2761//--------------------------------------------------------------------------------------//
2762
2763template <typename T, typename AllocatorT>
2766{
2767 if(this->node)
2768 this->node = this->node->next_sibling;
2769 return *this;
2770}
2771
2772//--------------------------------------------------------------------------------------//
2773
2774template <typename T, typename AllocatorT>
2777{
2778 if(this->node)
2779 {
2780 this->node = this->node->prev_sibling;
2781 }
2782 else
2783 {
2784 assert(m_parent);
2785 this->node = m_parent->last_child;
2786 }
2787 return *this;
2788}
2789
2790//--------------------------------------------------------------------------------------//
2791
2792template <typename T, typename AllocatorT>
2795{
2796 sibling_iterator copy = *this;
2797 ++(*this);
2798 return copy;
2799}
2800
2801//--------------------------------------------------------------------------------------//
2802
2803template <typename T, typename AllocatorT>
2806{
2807 sibling_iterator copy = *this;
2808 --(*this);
2809 return copy;
2810}
2811
2812//--------------------------------------------------------------------------------------//
2813
2814template <typename T, typename AllocatorT>
2817{
2818 while(num > 0)
2819 {
2820 ++(*this);
2821 --num;
2822 }
2823 return (*this);
2824}
2825
2826//--------------------------------------------------------------------------------------//
2827
2828template <typename T, typename AllocatorT>
2831{
2832 while(num > 0)
2833 {
2834 --(*this);
2835 --num;
2836 }
2837 return (*this);
2838}
2839
2840//--------------------------------------------------------------------------------------//
2841
2842template <typename T, typename AllocatorT>
2845{
2846 auto itr = *this;
2847 while(num > 0)
2848 {
2849 ++itr;
2850 --num;
2851 }
2852 return itr;
2853}
2854
2855//--------------------------------------------------------------------------------------//
2856
2857template <typename T, typename AllocatorT>
2860{
2861 return (m_parent) ? m_parent->last_child : nullptr;
2862}
2863
2864//--------------------------------------------------------------------------------------//
2865
2866template <typename T, typename AllocatorT>
2867size_t
2869{
2870 size_t i = 0;
2871 pre_order_iterator bit = begin();
2872 pre_order_iterator eit = end();
2873 pre_order_iterator itr = bit;
2874 while(itr != eit)
2875 {
2876 ++i;
2877 ++itr;
2878 }
2879 return i;
2880}
2881
2882//--------------------------------------------------------------------------------------//
2883
2884template <typename T>
2885void
2886print_graph_bracketed(const graph<T>& t, std::ostream& os = std::cout);
2887
2888//--------------------------------------------------------------------------------------//
2889
2890template <typename T>
2891void
2893 std::ostream& os = std::cout);
2894
2895//--------------------------------------------------------------------------------------//
2896// Iterate over all roots (the head) and print each one on a new line
2897// by calling printSingleRoot.
2898//--------------------------------------------------------------------------------------//
2899
2900template <typename T>
2901void
2902print_graph_bracketed(const graph<T>& t, std::ostream& os)
2903{
2904 int head_count = t.number_of_siblings(t.begin());
2905 int nhead = 0;
2906 for(typename graph<T>::sibling_iterator ritr = t.begin(); ritr != t.end();
2907 ++ritr, ++nhead)
2908 {
2909 print_subgraph_bracketed(t, ritr, os);
2910 if(nhead != head_count)
2911 {
2912 os << std::endl;
2913 }
2914 }
2915}
2916
2917//--------------------------------------------------------------------------------------//
2918// Print everything under this root in a flat, bracketed structure.
2919//--------------------------------------------------------------------------------------//
2920
2921template <typename T>
2922void
2924 std::ostream& os)
2925{
2926 static int _depth = 0;
2927 if(t.empty())
2928 return;
2929
2930 auto m_depth = _depth++;
2931 std::string indent = {};
2932 for(int i = 0; i < m_depth; ++i)
2933 indent += " ";
2934
2935 if(t.number_of_children(root) == 0)
2936 {
2937 os << "\n" << indent << *root;
2938 }
2939 else
2940 {
2941 // parent
2942 os << "\n" << indent << *root;
2943 os << "(";
2944 // child1, ..., childn
2945 int sibling_count = t.number_of_siblings(t.begin(root));
2946 int nsiblings;
2947 typename graph<T>::sibling_iterator children;
2948 for(children = t.begin(root), nsiblings = 0; children != t.end(root);
2949 ++children, ++nsiblings)
2950 {
2951 // recursively print child
2952 print_subgraph_bracketed(t, children, os);
2953 // comma after every child except the last one
2954 if(nsiblings != sibling_count)
2955 {
2956 os << ", ";
2957 }
2958 }
2959 os << ")";
2960 }
2961 --_depth;
2962}
2963
2964//--------------------------------------------------------------------------------------//
2965
2966template <typename T, typename Formatter = std::function<std::string(const T&)>>
2967void
2968print_graph(const tim::graph<T>& t, Formatter format, std::ostream& str = std::cout);
2969
2970//--------------------------------------------------------------------------------------//
2971
2972template <typename T, typename Formatter = std::function<std::string(const T&)>>
2973void
2974print_subgraph(const tim::graph<T>& t, Formatter format,
2975 typename tim::graph<T>::iterator root, std::ostream& str = std::cout);
2976
2977//--------------------------------------------------------------------------------------//
2978
2979template <typename T, typename Formatter>
2980void
2981print_graph(const tim::graph<T>& t, Formatter format, std::ostream& str)
2982{
2983 int head_count = t.number_of_siblings(t.begin());
2984 int nhead = 0;
2985 for(typename tim::graph<T>::sibling_iterator ritr = t.begin(); ritr != t.end();
2986 ++ritr, ++nhead)
2987 {
2988 print_subgraph(t, format, ritr, str);
2989 if(nhead != head_count)
2990 {
2991 str << std::endl;
2992 }
2993 }
2994}
2995
2996//--------------------------------------------------------------------------------------//
2997
2998template <typename T>
2999void
3000print_graph(const tim::graph<T>& t, std::ostream& str)
3001{
3002 auto _formatter = [](const T& obj) {
3003 std::stringstream ss;
3004 ss << obj;
3005 return ss.str();
3006 };
3007 int head_count = t.number_of_siblings(t.begin());
3008 int nhead = 0;
3009 for(typename tim::graph<T>::sibling_iterator ritr = t.begin(); ritr != t.end();
3010 ++ritr, ++nhead)
3011 {
3012 print_subgraph(t, _formatter, ritr, str);
3013 if(nhead != head_count)
3014 {
3015 str << std::endl;
3016 }
3017 }
3018}
3019
3020//--------------------------------------------------------------------------------------//
3021
3022template <typename T, typename Formatter>
3023void
3024print_subgraph(const tim::graph<T>& t, Formatter format,
3025 typename tim::graph<T>::iterator root, std::ostream& os)
3026{
3027 if(t.empty())
3028 return;
3029 if(t.number_of_children(root) == 0)
3030 {
3031 os << format(*root);
3032 }
3033 else
3034 {
3035 // parent
3036 std::string str = format(*root);
3037 if(str.length() > 0)
3038 os << str << "\n";
3039 // child1, ..., childn
3040 int sibling_count = t.number_of_siblings(t.begin(root));
3041 int nsiblings;
3042 typename tim::graph<T>::sibling_iterator children;
3043 for(children = t.begin(root), nsiblings = 0; children != t.end(root);
3044 ++children, ++nsiblings)
3045 {
3046 // recursively print child
3047 print_subgraph(t, format, children, os);
3048 // comma after every child except the last one
3049 if(nsiblings != sibling_count)
3050 {
3051 os << "\n";
3052 }
3053 }
3054 }
3055}
3056
3057//--------------------------------------------------------------------------------------//
3058
3059template <typename T, typename Formatter = std::function<std::string(const T&)>>
3060void
3061print_graph_hierarchy(const tim::graph<T>& t, Formatter format,
3062 std::ostream& str = std::cout);
3063
3064//--------------------------------------------------------------------------------------//
3065
3066template <typename T, typename Formatter = std::function<std::string(const T&)>>
3067void
3068print_subgraph_hierarchy(const tim::graph<T>& t, Formatter format,
3069 typename tim::graph<T>::iterator root,
3070 std::ostream& str = std::cout);
3071
3072//--------------------------------------------------------------------------------------//
3073
3074template <typename T, typename Formatter>
3075void
3076print_graph_hierarchy(const tim::graph<T>& t, Formatter format, std::ostream& str)
3077{
3078 int head_count = t.number_of_siblings(t.begin());
3079 int nhead = 0;
3080 for(typename tim::graph<T>::sibling_iterator ritr = t.begin(); ritr != t.end();
3081 ++ritr, ++nhead)
3082 {
3083 print_subgraph_hierarchy(t, format, ritr, str);
3084 if(nhead != head_count)
3085 {
3086 str << std::endl;
3087 }
3088 }
3089}
3090
3091//--------------------------------------------------------------------------------------//
3092
3093template <typename T, typename Formatter>
3094void
3095print_subgraph_hierarchy(const tim::graph<T>& t, Formatter format,
3096 typename tim::graph<T>::iterator root, std::ostream& os)
3097{
3098 if(t.empty())
3099 return;
3100 if(t.number_of_children(root) == 0)
3101 {
3102 os << format(*root);
3103 }
3104 else
3105 {
3106 // parent
3107 std::string str = format(*root);
3108 if(str.length() > 0)
3109 os << str << "\n" << std::setw(2 * (t.depth(root) + 1)) << "|_";
3110 // child1, ..., childn
3111 int sibling_count = t.number_of_siblings(t.begin(root));
3112 int nsiblings;
3113 typename tim::graph<T>::sibling_iterator children;
3114 for(children = t.begin(root), nsiblings = 0; children != t.end(root);
3115 ++children, ++nsiblings)
3116 {
3117 // recursively print child
3118 print_subgraph_hierarchy(t, format, children, os);
3119 // comma after every child except the last one
3120 if(nsiblings != sibling_count)
3121 {
3122 os << "\n" << std::setw(2 * (t.depth(root) + 1)) << "|_";
3123 }
3124 }
3125 }
3126}
3127
3128//--------------------------------------------------------------------------------------//
3129
3130} // namespace tim
3131
3132//--------------------------------------------------------------------------------------//
Base class for iterators, only pointers stored, no traversal logic.
Definition: graph.hpp:139
std::bidirectional_iterator_tag iterator_category
Definition: graph.hpp:146
iterator_base(iterator_base &&) noexcept=default
iterator_base(const iterator_base &)=default
sibling_iterator end() const
Definition: graph.hpp:2521
ptrdiff_t difference_type
Definition: graph.hpp:145
void skip_children()
When called, the next increment/decrement skips children of this node.
Definition: graph.hpp:2532
T * operator->() const
Definition: graph.hpp:2436
unsigned int number_of_children() const
Number of children of the node pointed to by the iterator.
Definition: graph.hpp:2550
sibling_iterator begin() const
Definition: graph.hpp:2507
Depth-first iterator, first accessing the node, then its children.
Definition: graph.hpp:187
pre_order_iterator & operator++()
Definition: graph.hpp:2613
bool operator!=(const pre_order_iterator &) const
Definition: graph.hpp:2445
pre_order_iterator & operator--()
Definition: graph.hpp:2638
pre_order_iterator(pre_order_iterator &&) noexcept=default
pre_order_iterator operator+(unsigned int)
Definition: graph.hpp:2710
bool operator==(const pre_order_iterator &) const
Definition: graph.hpp:2461
pre_order_iterator & operator+=(unsigned int)
Definition: graph.hpp:2682
pre_order_iterator & next_skip_children()
pre_order_iterator(const pre_order_iterator &)=default
pre_order_iterator & operator-=(unsigned int)
Definition: graph.hpp:2696
Iterator which traverses only the nodes which are siblings of each other.
Definition: graph.hpp:225
sibling_iterator & operator--()
Definition: graph.hpp:2776
sibling_iterator & operator-=(unsigned int)
Definition: graph.hpp:2830
sibling_iterator & operator+=(unsigned int)
Definition: graph.hpp:2816
sibling_iterator(sibling_iterator &&) noexcept=default
sibling_iterator operator+(unsigned int)
Definition: graph.hpp:2844
graph_node * range_last() const
Definition: graph.hpp:2859
sibling_iterator & operator++()
Definition: graph.hpp:2765
bool operator!=(const sibling_iterator &) const
Definition: graph.hpp:2477
bool operator==(const sibling_iterator &) const
Definition: graph.hpp:2492
sibling_iterator(const sibling_iterator &)=default
Arbitrary Graph / Tree (i.e. binary-tree but not binary). It is unlikely that this class will interac...
Definition: graph.hpp:115
graph_node * feet
Definition: graph.hpp:539
void clear()
Erase all nodes of the graph.
Definition: graph.hpp:631
void erase_children(const iterator_base &)
Erase all children of the node pointed to by iterator.
Definition: graph.hpp:644
bool equal_subgraph(const IterT &one, const IterT &two, BinaryPredicate) const
Definition: graph.hpp:2057
IterT append_child(IterT position)
Insert empty node as last/first child of node pointed to by position.
Definition: graph.hpp:789
size_t size() const
Count the total number of nodes.
Definition: graph.hpp:2868
IterT move_before(IterT target, IterT source)
Move 'source' node (plus its children) to become the previous sibling of 'target'.
Definition: graph.hpp:1621
bool empty() const
Check if graph is empty.
Definition: graph.hpp:2074
graph(const this_type &)=delete
void swap(sibling_iterator it)
Exchange the node (plus subgraph) with its sibling node (do nothing if no sibling present).
Definition: graph.hpp:2213
iterator::difference_type difference_type
Definition: graph.hpp:220
static bool is_head(const iterator_base &)
Determine whether the iterator is one of the 'head' nodes at the top level, i.e. has no parent.
Definition: graph.hpp:2328
IterT erase(IterT)
Erase element at position pointed to by iterator, return incremented iterator.
Definition: graph.hpp:666
IterT insert_after(IterT position, const T &x)
Insert node as next sibling of node pointed to by position.
Definition: graph.hpp:1180
static IterT next_sibling(IterT)
Return iterator to the next sibling of a node.
Definition: graph.hpp:776
pre_order_iterator end() const
Return iterator to the end of the graph.
Definition: graph.hpp:717
IterT move_in(IterT, graph &)
Inverse of take_out: inserts the given graph as previous sibling of indicated node by a move operatio...
Definition: graph.hpp:1770
graph(this_type &&) noexcept=default
IterT prepend_child(IterT position)
Definition: graph.hpp:820
static IterT previous_sibling(IterT)
Return iterator to the previous sibling of a node.
Definition: graph.hpp:763
static int depth(const iterator_base &)
Compute the depth to the root or to a fixed other iterator.
Definition: graph.hpp:2085
void reduce(const sibling_iterator &, const sibling_iterator &, std::set< sibling_iterator > &, ComparePred &&=[](sibling_iterator lhs, sibling_iterator rhs) { return(*lhs== *rhs);}, ReducePred &&=[](sibling_iterator lhs, sibling_iterator rhs) { *lhs+= *rhs;})
Reduce duplicate nodes.
Definition: graph.hpp:1940
int max_depth() const
Determine the maximal depth of the graph. An empty graph has max_depth=-1.
Definition: graph.hpp:2119
IterT prepend_children(IterT position, sibling_iterator from, sibling_iterator to)
Definition: graph.hpp:1033
IterT insert_subgraph_after(IterT position, const iterator_base &subgraph)
Insert node (with children) pointed to by subgraph as next sibling of node pointed to by position.
Definition: graph.hpp:1252
IterT append_children(IterT position, sibling_iterator from, const sibling_iterator &to)
Append the nodes in the from-to range (plus their children) as last/first children of position.
Definition: graph.hpp:1011
graph_node * head
Definition: graph.hpp:538
IterT reparent(IterT position, sibling_iterator begin, const sibling_iterator &end)
Move nodes in range to be children of 'position'.
Definition: graph.hpp:1463
static int depth(const iterator_base &, const iterator_base &)
Definition: graph.hpp:2102
pre_order_iterator iterator
The default iterator types throughout the graph class.
Definition: graph.hpp:218
bool equal(const IterT &one, const IterT &two, const IterT &three) const
Compare two ranges of nodes (compares nodes as well as graph structure).
Definition: graph.hpp:2009
static sibling_iterator child(const iterator_base &position, unsigned int)
Inverse of 'index': return the n-th child of the node at position.
Definition: graph.hpp:2397
void steal_resources(this_type &rhs)
Definition: graph.hpp:536
bool equal_subgraph(const IterT &one, const IterT &two) const
Definition: graph.hpp:2021
void merge(const sibling_iterator &, const sibling_iterator &, sibling_iterator, const sibling_iterator &, bool duplicate_leaves=false, bool first=false)
Merge with other graph, creating new branches and leaves only if they are not already present.
Definition: graph.hpp:1883
static unsigned int number_of_children(const iterator_base &)
Count the number of children of node at position.
Definition: graph.hpp:2172
bool is_in_subgraph(const iterator_base &position, const iterator_base &begin, const iterator_base &end) const
Determine whether node at position is in the subgraphs with root in the range.
IterT replace(IterT position, const T &x)
Replace node at 'position' with other node (keeping same children); 'position' becomes invalid.
Definition: graph.hpp:1279
IterT move_ontop(IterT target, IterT source)
Move 'source' node (plus its children) to become the node at 'target' (erasing the node at 'target').
Definition: graph.hpp:1675
void serialize(Archive &ar, const unsigned int)
Definition: graph.hpp:530
IterT move_in_as_nth_child(IterT, size_t, graph &)
As above, but now make the graph the nth child of the indicated node (if possible).
Definition: graph.hpp:1808
void subgraph(graph &, sibling_iterator from, sibling_iterator to) const
pre_order_iterator set_head(const T &x)
Short-hand to insert topmost node in otherwise empty graph.
Definition: graph.hpp:1057
graph subgraph(sibling_iterator from, sibling_iterator to) const
Extract a new graph formed by the range of siblings plus all their children.
IterT flatten(IterT position)
Move all children of node at 'position' to be siblings, returns position.
Definition: graph.hpp:1430
graph(const iterator_base &)
Definition: graph.hpp:573
bool equal(const IterT &one, const IterT &two, const IterT &three, BinaryPredicate) const
Definition: graph.hpp:2032
graph(const T &)
Definition: graph.hpp:564
static IterT parent(IterT)
Return iterator to the parent of a node.
Definition: graph.hpp:752
IterT insert_subgraph(IterT position, const iterator_base &subgraph)
Insert node (with children) pointed to by subgraph as previous sibling of node pointed to by position...
Definition: graph.hpp:1239
IterT wrap(IterT position, const T &x)
Replace node with a new node, making the old node (plus subgraph) a child of the new node.
Definition: graph.hpp:1538
unsigned int number_of_siblings(const iterator_base &) const
Count the number of siblings (left and right) of node at iterator. Total nodes at this level is +1.
Definition: graph.hpp:2188
IterT insert(IterT position, const T &x)
Insert node as previous sibling of node pointed to by position.
Definition: graph.hpp:1078
T value_type
Value of the data stored at a node.
Definition: graph.hpp:122
IterT move_in_below(IterT, graph &)
As above, but now make the graph a child of the indicated node.
sibling_iterator sibling(const iterator_base &position, unsigned int) const
Return iterator to the sibling indicated by index.
Definition: graph.hpp:2369
void swap(iterator, iterator)
Exchange two nodes (plus subgraphs). The iterators will remain valid and keep pointing to the same no...
Definition: graph.hpp:2246
unsigned int index(sibling_iterator it) const
Determine the index of a node in the range of siblings to which it belongs.
Definition: graph.hpp:2339
pre_order_iterator begin() const
Return iterator to the beginning of the graph.
Definition: graph.hpp:708
int max_depth(const iterator_base &) const
Determine the maximal depth of the graph with top node at the given position.
Definition: graph.hpp:2132
graph move_out(iterator)
Extract the subgraph starting at the indicated node, removing it from the original graph.
Definition: graph.hpp:1742
IterT move_after(IterT target, IterT source)
Move 'source' node (plus its children) to become the next sibling of 'target'.
Definition: graph.hpp:1567
bool is_valid(const iterator_base &) const
Determine whether the iterator is an 'end' iterator and thus not actually pointing to a node.
Definition: graph.hpp:2313
A node in the graph, combining links to other nodes as well as the actual data.
Definition: graph.hpp:59
tgraph_node(tgraph_node &&)=default
tgraph_node()=default
tgraph_node< T > * last_child
Definition: graph.hpp:80
tgraph_node< T > * next_sibling
Definition: graph.hpp:82
void serialize(Archive &ar, const unsigned int)
Definition: graph.hpp:88
tgraph_node & operator=(tgraph_node &&)=default
tgraph_node< T > * prev_sibling
Definition: graph.hpp:81
~tgraph_node()=default
tgraph_node< T > * parent
Definition: graph.hpp:78
tgraph_node< T > * first_child
Definition: graph.hpp:79
tgraph_node(const tgraph_node &)=delete
tgraph_node & operator=(const tgraph_node &)=delete
STL namespace.
::tim::statistics< Tp > max(::tim::statistics< Tp > lhs, const Tp &rhs)
Definition: statistics.hpp:320
return false
Definition: definition.hpp:326
auto destroy(TupleT< Tp... > &obj)
Definition: functional.cpp:282
Lhs operator*(Lhs, const Rhs &)
Definition: stl.hpp:295
Definition: kokkosp.cpp:39
void print_graph(const tim::graph< T > &t, Formatter format, std::ostream &str=std::cout)
Definition: graph.hpp:2981
void print_graph_bracketed(const graph< T > &t, std::ostream &os=std::cout)
Definition: graph.hpp:2902
tim::mpl::apply< std::string > string
Definition: macros.hpp:53
size_t pos
Definition: config.cpp:102
void print_graph_hierarchy(const tim::graph< T > &t, Formatter format, std::ostream &str=std::cout)
Definition: graph.hpp:3076
const std::string std::ostream * os
void print_subgraph_bracketed(const graph< T > &t, typename graph< T >::iterator root, std::ostream &os=std::cout)
Definition: graph.hpp:2923
void print_subgraph(const tim::graph< T > &t, Formatter format, typename tim::graph< T >::iterator root, std::ostream &str=std::cout)
Definition: graph.hpp:3024
void print_subgraph_hierarchy(const tim::graph< T > &t, Formatter format, typename tim::graph< T >::iterator root, std::ostream &str=std::cout)
Definition: graph.hpp:3095
Declare the storage types.
static auto release(std::shared_ptr< AllocT > &_v)
typename typename typename
Definition: types.hpp:226