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