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.
tim::graph< T, AllocatorT > Class Template Reference

Arbitrary Graph / Tree (i.e. binary-tree but not binary). It is unlikely that this class will interacted with directly. More...

#include "timemory/storage/graph.hpp"

+ Collaboration diagram for tim::graph< T, AllocatorT >:

Classes

class  iterator_base
 Base class for iterators, only pointers stored, no traversal logic. More...
 
class  pre_order_iterator
 Depth-first iterator, first accessing the node, then its children. More...
 
class  sibling_iterator
 Iterator which traverses only the nodes which are siblings of each other. More...
 

Public Types

using value_type = T
 Value of the data stored at a node. More...
 
typedef pre_order_iterator iterator
 The default iterator types throughout the graph class. More...
 
typedef const iterator const_iterator
 
typedef iterator::difference_type difference_type
 

Public Member Functions

 graph ()
 
 graph (const T &)
 
 graph (const iterator_base &)
 
 graph (const graph< T, AllocatorT > &)
 
 graph (graph< T, AllocatorT > &&) noexcept
 
 ~graph ()
 
graph< T, AllocatorT > & operator= (const graph< T, AllocatorT > &)
 
graph< T, AllocatorT > & operator= (graph< T, AllocatorT > &&) noexcept
 
pre_order_iterator begin () const
 Return iterator to the beginning of the graph. More...
 
pre_order_iterator end () const
 Return iterator to the end of the graph. More...
 
void clear ()
 Erase all nodes of the graph. More...
 
template<typename IterT >
IterT erase (IterT)
 Erase element at position pointed to by iterator, return incremented iterator. More...
 
void erase_children (const iterator_base &)
 Erase all children of the node pointed to by iterator. More...
 
template<typename IterT >
IterT append_child (IterT position)
 Insert empty node as last/first child of node pointed to by position. More...
 
template<typename IterT >
IterT prepend_child (IterT position)
 
template<typename IterT >
IterT append_child (IterT position, const T &x)
 Insert node as last/first child of node pointed to by position. More...
 
template<typename IterT >
IterT append_child (IterT position, T &&x)
 
template<typename IterT >
IterT prepend_child (IterT position, const T &x)
 
template<typename IterT >
IterT prepend_child (IterT position, T &&x)
 
template<typename IterT >
IterT append_child (IterT position, IterT other_position)
 Append the node (plus its children) at other_position as last/first child of position. More...
 
template<typename IterT >
IterT prepend_child (IterT position, IterT other_position)
 
template<typename IterT >
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. More...
 
template<typename IterT >
IterT prepend_children (IterT position, sibling_iterator from, sibling_iterator to)
 
pre_order_iterator set_head (const T &x)
 Short-hand to insert topmost node in otherwise empty graph. More...
 
pre_order_iterator set_head (T &&x)
 
template<typename IterT >
IterT insert (IterT position, const T &x)
 Insert node as previous sibling of node pointed to by position. More...
 
template<typename IterT >
IterT insert (IterT position, T &&x)
 
sibling_iterator insert (sibling_iterator position, const T &x)
 Specialisation of previous member. More...
 
template<typename IterT >
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. Does not change the subgraph itself (use move_in or move_in_below for that). More...
 
template<typename IterT >
IterT insert_after (IterT position, const T &x)
 Insert node as next sibling of node pointed to by position. More...
 
template<typename IterT >
IterT insert_after (IterT position, T &&x)
 
template<typename IterT >
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. More...
 
template<typename IterT >
IterT replace (IterT position, const T &x)
 Replace node at 'position' with other node (keeping same children); 'position' becomes invalid. More...
 
template<typename IterT >
IterT replace (IterT position, T &&x)
 
template<typename IterT >
IterT replace (IterT position, const iterator_base &from)
 Replace node at 'position' with subgraph starting at 'from' (do not erase subgraph at 'from'); see above. More...
 
sibling_iterator replace (sibling_iterator orig_begin, const sibling_iterator &orig_end, sibling_iterator new_begin, const sibling_iterator &new_end)
 Replace string of siblings (plus their children) with copy of a new string (with children); see above. More...
 
template<typename IterT >
IterT flatten (IterT position)
 Move all children of node at 'position' to be siblings, returns position. More...
 
template<typename IterT >
IterT reparent (IterT position, sibling_iterator begin, const sibling_iterator &end)
 Move nodes in range to be children of 'position'. More...
 
template<typename IterT >
IterT reparent (IterT position, IterT from)
 Move all child nodes of 'from' to be children of 'position'. More...
 
template<typename IterT >
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. More...
 
template<typename IterT >
IterT wrap (IterT from, IterT to, const T &x)
 Replace the range of sibling nodes (plus subgraphs), making these children of the new node. More...
 
template<typename IterT >
IterT move_after (IterT target, IterT source)
 Move 'source' node (plus its children) to become the next sibling of 'target'. More...
 
template<typename IterT >
IterT move_before (IterT target, IterT source)
 Move 'source' node (plus its children) to become the previous sibling of 'target'. More...
 
sibling_iterator move_before (sibling_iterator target, sibling_iterator source)
 
template<typename IterT >
IterT move_ontop (IterT target, IterT source)
 Move 'source' node (plus its children) to become the node at 'target' (erasing the node at 'target'). More...
 
graph move_out (iterator)
 Extract the subgraph starting at the indicated node, removing it from the original graph. More...
 
template<typename IterT >
IterT move_in (IterT, graph &)
 Inverse of take_out: inserts the given graph as previous sibling of indicated node by a move operation, that is, the given graph becomes empty. Returns iterator to the top node. More...
 
template<typename IterT >
IterT move_in_below (IterT, graph &)
 As above, but now make the graph a child of the indicated node. More...
 
template<typename IterT >
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). More...
 
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. More...
 
template<typename ComparePred = std::function<bool(sibling_iterator, sibling_iterator)>, typename ReducePred = std::function<void(sibling_iterator, sibling_iterator)>>
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. More...
 
template<typename IterT >
bool equal (const IterT &one, const IterT &two, const IterT &three) const
 Compare two ranges of nodes (compares nodes as well as graph structure). More...
 
template<typename IterT , typename BinaryPredicate >
bool equal (const IterT &one, const IterT &two, const IterT &three, BinaryPredicate) const
 
template<typename IterT >
bool equal_subgraph (const IterT &one, const IterT &two) const
 
template<typename IterT , typename BinaryPredicate >
bool equal_subgraph (const IterT &one, const IterT &two, BinaryPredicate) const
 
graph subgraph (sibling_iterator from, sibling_iterator to) const
 Extract a new graph formed by the range of siblings plus all their children. More...
 
void subgraph (graph &, sibling_iterator from, sibling_iterator to) const
 
void swap (sibling_iterator it)
 Exchange the node (plus subgraph) with its sibling node (do nothing if no sibling present). More...
 
void swap (iterator, iterator)
 Exchange two nodes (plus subgraphs). The iterators will remain valid and keep pointing to the same nodes, which now sit at different locations in the graph. More...
 
size_t size () const
 Count the total number of nodes. More...
 
bool empty () const
 Check if graph is empty. More...
 
int max_depth () const
 Determine the maximal depth of the graph. An empty graph has max_depth=-1. More...
 
int max_depth (const iterator_base &) const
 Determine the maximal depth of the graph with top node at the given position. More...
 
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. More...
 
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. More...
 
bool is_valid (const iterator_base &) const
 Determine whether the iterator is an 'end' iterator and thus not actually pointing to a node. More...
 
unsigned int index (sibling_iterator it) const
 Determine the index of a node in the range of siblings to which it belongs. More...
 
sibling_iterator sibling (const iterator_base &position, unsigned int) const
 Return iterator to the sibling indicated by index. More...
 
template<typename Archive >
void serialize (Archive &ar, const unsigned int)
 

Static Public Member Functions

static sibling_iterator begin (const iterator_base &)
 Return sibling iterator to the first child of given node. More...
 
static sibling_iterator end (const iterator_base &)
 Return sibling end iterator for children of given node. More...
 
template<typename IterT >
static IterT parent (IterT)
 Return iterator to the parent of a node. More...
 
template<typename IterT >
static IterT previous_sibling (IterT)
 Return iterator to the previous sibling of a node. More...
 
template<typename IterT >
static IterT next_sibling (IterT)
 Return iterator to the next sibling of a node. More...
 
static int depth (const iterator_base &)
 Compute the depth to the root or to a fixed other iterator. More...
 
static int depth (const iterator_base &, const iterator_base &)
 
static unsigned int number_of_children (const iterator_base &)
 Count the number of children of node at position. More...
 
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. More...
 
static sibling_iterator child (const iterator_base &position, unsigned int)
 Inverse of 'index': return the n-th child of the node at position. More...
 

Public Attributes

graph_nodehead
 
graph_nodefeet
 

Protected Types

using graph_node = tgraph_node< T >
 

Detailed Description

template<typename T, typename AllocatorT>
class tim::graph< T, AllocatorT >

Arbitrary Graph / Tree (i.e. binary-tree but not binary). It is unlikely that this class will interacted with directly.

Definition at line 335 of file graph.hpp.

Member Typedef Documentation

◆ const_iterator

template<typename T , typename AllocatorT >
typedef const iterator tim::graph< T, AllocatorT >::const_iterator

Definition at line 439 of file graph.hpp.

◆ difference_type

template<typename T , typename AllocatorT >
typedef iterator::difference_type tim::graph< T, AllocatorT >::difference_type

Definition at line 440 of file graph.hpp.

◆ graph_node

template<typename T , typename AllocatorT >
using tim::graph< T, AllocatorT >::graph_node = tgraph_node<T>
protected

Definition at line 338 of file graph.hpp.

◆ iterator

template<typename T , typename AllocatorT >
typedef pre_order_iterator tim::graph< T, AllocatorT >::iterator

The default iterator types throughout the graph class.

Definition at line 438 of file graph.hpp.

◆ value_type

template<typename T , typename AllocatorT >
using tim::graph< T, AllocatorT >::value_type = T

Value of the data stored at a node.

Definition at line 342 of file graph.hpp.

Constructor & Destructor Documentation

◆ graph() [1/5]

template<typename T , typename AllocatorT >
tim::graph< T, AllocatorT >::graph

Definition at line 775 of file graph.hpp.

776 {
777  m_head_initialize();
778 }

◆ graph() [2/5]

template<typename T , typename AllocatorT >
tim::graph< T, AllocatorT >::graph ( const T &  x)

Definition at line 783 of file graph.hpp.

784 {
785  m_head_initialize();
786  set_head(x);
787 }
pre_order_iterator set_head(const T &x)
Short-hand to insert topmost node in otherwise empty graph.
Definition: graph.hpp:1346

References tim::graph< T, AllocatorT >::set_head().

◆ graph() [3/5]

template<typename T , typename AllocatorT >
tim::graph< T, AllocatorT >::graph ( const iterator_base other)

Definition at line 809 of file graph.hpp.

810 {
811  m_head_initialize();
812  set_head((*other));
813  replace(begin(), other);
814 }
IterT replace(IterT position, const T &x)
Replace node at 'position' with other node (keeping same children); 'position' becomes invalid.
Definition: graph.hpp:1568
pre_order_iterator begin() const
Return iterator to the beginning of the graph.
Definition: graph.hpp:997

References tim::graph< T, AllocatorT >::iterator_base::begin(), tim::graph< T, AllocatorT >::replace(), and tim::graph< T, AllocatorT >::set_head().

◆ graph() [4/5]

template<typename T , typename AllocatorT >
tim::graph< T, AllocatorT >::graph ( const graph< T, AllocatorT > &  other)

Definition at line 885 of file graph.hpp.

886 {
887  // allocator_traits::reserve(2 + other.size());
888  m_head_initialize();
889  m_copy(other);
890 }

◆ graph() [5/5]

template<typename T , typename AllocatorT >
tim::graph< T, AllocatorT >::graph ( graph< T, AllocatorT > &&  x)
noexcept

Definition at line 792 of file graph.hpp.

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 }
graph_node * feet
Definition: graph.hpp:750
graph_node * head
Definition: graph.hpp:749
tgraph_node< T > * next_sibling
Definition: graph.hpp:80
tgraph_node< T > * prev_sibling
Definition: graph.hpp:79

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, tim::tgraph_node< T >::next_sibling, and tim::tgraph_node< T >::prev_sibling.

◆ ~graph()

template<typename T , typename AllocatorT >
tim::graph< T, AllocatorT >::~graph

Definition at line 819 of file graph.hpp.

820 {
821  clear();
824  allocator_traits::deallocate(m_alloc, head, 1);
825  allocator_traits::deallocate(m_alloc, feet, 1);
826 }
void clear()
Erase all nodes of the graph.
Definition: graph.hpp:923
auto destroy(TupleT< Tp... > &obj)
Definition: functional.cpp:264

References tim::graph< T, AllocatorT >::clear(), tim::invoke::destroy(), tim::graph< T, AllocatorT >::feet, and tim::graph< T, AllocatorT >::head.

Member Function Documentation

◆ append_child() [1/4]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::append_child ( IterT  position)
inline

Insert empty node as last/first child of node pointed to by position.

Definition at line 1078 of file graph.hpp.

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 }
tgraph_node< T > graph_node
Definition: graph.hpp:338

References tim::graph< T, AllocatorT >::feet, and tim::graph< T, AllocatorT >::head.

Referenced by tim::graph_data< NodeT >::append_child(), tim::graph< T, AllocatorT >::append_child(), tim::graph_data< NodeT >::append_head(), tim::graph_data< NodeT >::emplace_child(), and tim::graph< T, AllocatorT >::merge().

◆ append_child() [2/4]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::append_child ( IterT  position,
const T &  x 
)
inline

Insert node as last/first child of node pointed to by position.

Definition at line 1140 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, and tim::graph< T, AllocatorT >::head.

◆ append_child() [3/4]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::append_child ( IterT  position,
IterT  other_position 
)
inline

Append the node (plus its children) at other_position as last/first child of position.

Definition at line 1270 of file graph.hpp.

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 }
IterT append_child(IterT position)
Insert empty node as last/first child of node pointed to by position.
Definition: graph.hpp:1078
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
T value_type
Value of the data stored at a node.
Definition: graph.hpp:342

References tim::graph< T, AllocatorT >::append_child(), tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, and tim::graph< T, AllocatorT >::move_ontop().

◆ append_child() [4/4]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::append_child ( IterT  position,
T &&  x 
)
inline

Definition at line 1175 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, and tim::graph< T, AllocatorT >::head.

◆ append_children()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::append_children ( IterT  position,
sibling_iterator  from,
const sibling_iterator to 
)
inline

Append the nodes in the from-to range (plus their children) as last/first children of position.

Definition at line 1300 of file graph.hpp.

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 }
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

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, and tim::graph< T, AllocatorT >::insert_subgraph().

◆ begin() [1/2]

◆ begin() [2/2]

template<typename T , typename AllocatorT >
graph< T, AllocatorT >::sibling_iterator tim::graph< T, AllocatorT >::begin ( const iterator_base pos)
static

Return sibling iterator to the first child of given node.

Definition at line 1015 of file graph.hpp.

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 }
pre_order_iterator end() const
Return iterator to the end of the graph.
Definition: graph.hpp:1006
size_t pos
Definition: definition.hpp:129

References tim::graph< T, AllocatorT >::iterator_base::end(), and tim::pos.

◆ child()

template<typename T , typename AllocatorT >
graph< T, AllocatorT >::sibling_iterator tim::graph< T, AllocatorT >::child ( const iterator_base position,
unsigned int  num 
)
static

Inverse of 'index': return the n-th child of the node at position.

Definition at line 2686 of file graph.hpp.

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 }

References tim::tgraph_node< T >::first_child, tim::tgraph_node< T >::next_sibling, and tim::graph< T, AllocatorT >::iterator_base::node.

◆ clear()

template<typename T , typename AllocatorT >
void tim::graph< T, AllocatorT >::clear
inline

Erase all nodes of the graph.

Definition at line 923 of file graph.hpp.

924 {
925  if(head)
926  {
927  while(head->next_sibling != feet)
928  erase(pre_order_iterator(head->next_sibling));
929  }
930 }
IterT erase(IterT)
Erase element at position pointed to by iterator, return incremented iterator.
Definition: graph.hpp:958

References tim::graph< T, AllocatorT >::pre_order_iterator::pre_order_iterator(), tim::graph< T, AllocatorT >::erase(), tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, and tim::tgraph_node< T >::next_sibling.

Referenced by tim::graph< T, AllocatorT >::~graph(), tim::graph_data< NodeT >::~graph_data(), and tim::graph_data< NodeT >::clear().

◆ depth() [1/2]

template<typename T , typename AllocatorT >
int tim::graph< T, AllocatorT >::depth ( const iterator_base it)
static

Compute the depth to the root or to a fixed other iterator.

Definition at line 2374 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::iterator_base::node, and tim::pos.

Referenced by tim::print_subgraph_hierarchy().

◆ depth() [2/2]

template<typename T , typename AllocatorT >
int tim::graph< T, AllocatorT >::depth ( const iterator_base it,
const iterator_base root 
)
static

Definition at line 2391 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::iterator_base::node, and tim::pos.

◆ empty()

template<typename T , typename AllocatorT >
bool tim::graph< T, AllocatorT >::empty
inline

Check if graph is empty.

Definition at line 2363 of file graph.hpp.

2364 {
2365  pre_order_iterator it = begin();
2366  pre_order_iterator eit = end();
2367  return (it == eit);
2368 }

References tim::graph< T, AllocatorT >::iterator_base::begin(), and tim::graph< T, AllocatorT >::iterator_base::end().

Referenced by tim::print_subgraph(), tim::print_subgraph_bracketed(), and tim::print_subgraph_hierarchy().

◆ end() [1/2]

◆ end() [2/2]

template<typename T , typename AllocatorT >
graph< T, AllocatorT >::sibling_iterator tim::graph< T, AllocatorT >::end ( const iterator_base pos)
static

Return sibling end iterator for children of given node.

Definition at line 1029 of file graph.hpp.

1030 {
1031  sibling_iterator ret(nullptr);
1032  ret.m_parent = pos.node;
1033  return ret;
1034 }

References tim::graph< T, AllocatorT >::sibling_iterator::m_parent, and tim::pos.

◆ equal() [1/2]

template<typename T , typename AllocatorT >
template<typename IterT >
bool tim::graph< T, AllocatorT >::equal ( const IterT &  one,
const IterT &  two,
const IterT &  three 
) const
inline

Compare two ranges of nodes (compares nodes as well as graph structure).

Definition at line 2298 of file graph.hpp.

2300 {
2301  std::equal_to<T> comp;
2302  return equal(one_, two, three_, comp);
2303 }
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

Referenced by tim::graph< T, AllocatorT >::equal_subgraph().

◆ equal() [2/2]

template<typename T , typename AllocatorT >
template<typename IterT , typename BinaryPredicate >
bool tim::graph< T, AllocatorT >::equal ( const IterT &  one,
const IterT &  two,
const IterT &  three,
BinaryPredicate  fun 
) const
inline

Definition at line 2321 of file graph.hpp.

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 }
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

References tim::graph< T, AllocatorT >::is_valid(), and tim::graph< T, AllocatorT >::iterator_base::number_of_children().

◆ equal_subgraph() [1/2]

template<typename T , typename AllocatorT >
template<typename IterT >
bool tim::graph< T, AllocatorT >::equal_subgraph ( const IterT &  one,
const IterT &  two 
) const
inline

Definition at line 2310 of file graph.hpp.

2311 {
2312  std::equal_to<T> comp;
2313  return equal_subgraph(one_, two_, comp);
2314 }
bool equal_subgraph(const IterT &one, const IterT &two) const
Definition: graph.hpp:2310

◆ equal_subgraph() [2/2]

template<typename T , typename AllocatorT >
template<typename IterT , typename BinaryPredicate >
bool tim::graph< T, AllocatorT >::equal_subgraph ( const IterT &  one,
const IterT &  two,
BinaryPredicate  fun 
) const
inline

Definition at line 2346 of file graph.hpp.

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 }
static unsigned int number_of_children(const iterator_base &)
Count the number of children of node at position.
Definition: graph.hpp:2461

References tim::graph< T, AllocatorT >::iterator_base::begin(), tim::graph< T, AllocatorT >::iterator_base::end(), tim::graph< T, AllocatorT >::equal(), and tim::graph< T, AllocatorT >::iterator_base::number_of_children().

◆ erase()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::erase ( IterT  it)
inline

Erase element at position pointed to by iterator, return incremented iterator.

Definition at line 958 of file graph.hpp.

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 }
void erase_children(const iterator_base &)
Erase all children of the node pointed to by iterator.
Definition: graph.hpp:936

References tim::invoke::destroy(), tim::graph< T, AllocatorT >::erase_children(), tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, tim::tgraph_node< T >::next_sibling, tim::tgraph_node< T >::parent, and tim::tgraph_node< T >::prev_sibling.

Referenced by tim::graph< T, AllocatorT >::clear(), tim::graph< T, AllocatorT >::erase_children(), tim::graph< T, AllocatorT >::move_ontop(), tim::graph< T, AllocatorT >::reduce(), and tim::graph< T, AllocatorT >::replace().

◆ erase_children()

template<typename T , typename AllocatorT >
void tim::graph< T, AllocatorT >::erase_children ( const iterator_base it)
inline

Erase all children of the node pointed to by iterator.

Definition at line 936 of file graph.hpp.

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)
946  erase(pre_order_iterator(cur->next_sibling));
947  }
948 
949  it.node->first_child = nullptr;
950  it.node->last_child = nullptr;
951 }

References tim::graph< T, AllocatorT >::pre_order_iterator::pre_order_iterator(), tim::graph< T, AllocatorT >::erase(), tim::graph< T, AllocatorT >::feet, tim::tgraph_node< T >::first_child, tim::tgraph_node< T >::last_child, tim::tgraph_node< T >::next_sibling, and tim::graph< T, AllocatorT >::iterator_base::node.

Referenced by tim::graph< T, AllocatorT >::erase(), tim::graph< T, AllocatorT >::replace(), and tim::graph_data< NodeT >::reset().

◆ flatten()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::flatten ( IterT  position)
inline

Move all children of node at 'position' to be siblings, returns position.

Definition at line 1719 of file graph.hpp.

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 }

References tim::tgraph_node< T >::first_child, tim::tgraph_node< T >::next_sibling, and tim::tgraph_node< T >::parent.

◆ index()

template<typename T , typename AllocatorT >
unsigned int tim::graph< T, AllocatorT >::index ( sibling_iterator  it) const
inline

Determine the index of a node in the range of siblings to which it belongs.

Definition at line 2628 of file graph.hpp.

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 }

References tim::tgraph_node< T >::next_sibling, tim::graph< T, AllocatorT >::iterator_base::node, tim::tgraph_node< T >::parent, and tim::tgraph_node< T >::prev_sibling.

Referenced by tim::graph< T, AllocatorT >::reduce().

◆ insert() [1/3]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::insert ( IterT  position,
const T &  x 
)
inline

Insert node as previous sibling of node pointed to by position.

Definition at line 1367 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, and tim::graph< T, AllocatorT >::head.

Referenced by tim::graph< T, AllocatorT >::insert_subgraph(), tim::graph< T, AllocatorT >::set_head(), and tim::graph< T, AllocatorT >::wrap().

◆ insert() [2/3]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::insert ( IterT  position,
T &&  x 
)
inline

Definition at line 1401 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet.

◆ insert() [3/3]

template<typename T , typename AllocatorT >
graph< T, AllocatorT >::sibling_iterator tim::graph< T, AllocatorT >::insert ( sibling_iterator  position,
const T &  x 
)
inline

Specialisation of previous member.

Definition at line 1433 of file graph.hpp.

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 }

◆ insert_after() [1/2]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::insert_after ( IterT  position,
const T &  x 
)
inline

Insert node as next sibling of node pointed to by position.

Definition at line 1469 of file graph.hpp.

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 }

Referenced by tim::graph_data< NodeT >::add_dummy(), and tim::graph< T, AllocatorT >::insert_subgraph_after().

◆ insert_after() [2/2]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::insert_after ( IterT  position,
T &&  x 
)
inline

Definition at line 1498 of file graph.hpp.

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 }

◆ insert_subgraph()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::insert_subgraph ( IterT  position,
const iterator_base subgraph 
)
inline

Insert node (with children) pointed to by subgraph as previous sibling of node pointed to by position. Does not change the subgraph itself (use move_in or move_in_below for that).

Definition at line 1528 of file graph.hpp.

1529 {
1530  // insert dummy
1531  IterT it = insert(position, value_type{});
1532  // replace dummy with subgraph
1533  return replace(it, _subgraph);
1534 }
IterT insert(IterT position, const T &x)
Insert node as previous sibling of node pointed to by position.
Definition: graph.hpp:1367

References tim::graph< T, AllocatorT >::insert(), and tim::graph< T, AllocatorT >::replace().

Referenced by tim::graph< T, AllocatorT >::append_children(), tim::graph< T, AllocatorT >::merge(), tim::graph< T, AllocatorT >::prepend_children(), and tim::graph< T, AllocatorT >::replace().

◆ insert_subgraph_after()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::insert_subgraph_after ( IterT  position,
const iterator_base subgraph 
)
inline

Insert node (with children) pointed to by subgraph as next sibling of node pointed to by position.

Definition at line 1541 of file graph.hpp.

1543 {
1544  // insert dummy
1545  IterT it = insert_after(position, value_type{});
1546  // replace dummy with subgraph
1547  return replace(it, _subgraph);
1548 }
IterT insert_after(IterT position, const T &x)
Insert node as next sibling of node pointed to by position.
Definition: graph.hpp:1469

References tim::graph< T, AllocatorT >::insert_after(), and tim::graph< T, AllocatorT >::replace().

Referenced by tim::graph< T, AllocatorT >::reduce().

◆ is_head()

template<typename T , typename AllocatorT >
bool tim::graph< T, AllocatorT >::is_head ( const iterator_base it)
static

Determine whether the iterator is one of the 'head' nodes at the top level, i.e. has no parent.

Definition at line 2617 of file graph.hpp.

2618 {
2619  if(it.node->parent == nullptr)
2620  return true;
2621  return false;
2622 }

References tim::graph< T, AllocatorT >::iterator_base::node, and tim::tgraph_node< T >::parent.

Referenced by tim::graph_data< NodeT >::pop_graph().

◆ is_in_subgraph()

template<typename T , typename AllocatorT >
bool tim::graph< T, AllocatorT >::is_in_subgraph ( const iterator_base position,
const iterator_base begin,
const iterator_base end 
) const
inline

Determine whether node at position is in the subgraphs with root in the range.

◆ is_valid()

template<typename T , typename AllocatorT >
bool tim::graph< T, AllocatorT >::is_valid ( const iterator_base it) const
inline

Determine whether the iterator is an 'end' iterator and thus not actually pointing to a node.

Definition at line 2602 of file graph.hpp.

2603 {
2604  if(it.node == nullptr || it.node == feet || it.node == head)
2605  {
2606  return false;
2607  }
2608  {
2609  return true;
2610  }
2611 }

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, and tim::graph< T, AllocatorT >::iterator_base::node.

Referenced by tim::graph< T, AllocatorT >::equal(), and tim::graph< T, AllocatorT >::reduce().

◆ max_depth() [1/2]

template<typename T , typename AllocatorT >
int tim::graph< T, AllocatorT >::max_depth
inline

Determine the maximal depth of the graph. An empty graph has max_depth=-1.

Definition at line 2408 of file graph.hpp.

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 }
int max_depth() const
Determine the maximal depth of the graph. An empty graph has max_depth=-1.
Definition: graph.hpp:2408
::tim::statistics< Tp > max(::tim::statistics< Tp > lhs, const Tp &rhs)
Definition: statistics.hpp:310

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, and tim::tgraph_node< T >::next_sibling.

◆ max_depth() [2/2]

template<typename T , typename AllocatorT >
int tim::graph< T, AllocatorT >::max_depth ( const iterator_base pos) const
inline

Determine the maximal depth of the graph with top node at the given position.

Definition at line 2421 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, tim::tgraph_node< T >::first_child, tim::graph< T, AllocatorT >::head, tim::tgraph_node< T >::next_sibling, tim::tgraph_node< T >::parent, and tim::pos.

◆ merge()

template<typename T , typename AllocatorT >
void tim::graph< T, AllocatorT >::merge ( const sibling_iterator to1,
const sibling_iterator to2,
sibling_iterator  from1,
const sibling_iterator from2,
bool  duplicate_leaves = false,
bool  first = false 
)
inline

Merge with other graph, creating new branches and leaves only if they are not already present.

Definition at line 2172 of file graph.hpp.

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 }
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 IterT parent(IterT)
Return iterator to the parent of a node.
Definition: graph.hpp:1041
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

References tim::graph< T, AllocatorT >::append_child(), tim::graph< T, AllocatorT >::iterator_base::begin(), tim::graph< T, AllocatorT >::iterator_base::end(), tim::graph< T, AllocatorT >::insert_subgraph(), tim::graph< T, AllocatorT >::number_of_siblings(), and tim::graph< T, AllocatorT >::parent().

◆ move_after()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::move_after ( IterT  target,
IterT  source 
)
inline

Move 'source' node (plus its children) to become the next sibling of 'target'.

Definition at line 1856 of file graph.hpp.

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 }

References tim::tgraph_node< T >::next_sibling, tim::tgraph_node< T >::parent, and tim::tgraph_node< T >::prev_sibling.

◆ move_before() [1/2]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::move_before ( IterT  target,
IterT  source 
)
inline

Move 'source' node (plus its children) to become the previous sibling of 'target'.

Definition at line 1910 of file graph.hpp.

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 }

References tim::tgraph_node< T >::next_sibling, tim::tgraph_node< T >::parent, and tim::tgraph_node< T >::prev_sibling.

◆ move_before() [2/2]

template<typename T , typename AllocatorT >
sibling_iterator tim::graph< T, AllocatorT >::move_before ( sibling_iterator  target,
sibling_iterator  source 
)
inline

◆ move_in()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::move_in ( IterT  loc,
graph< T, AllocatorT > &  other 
)
inline

Inverse of take_out: inserts the given graph as previous sibling of indicated node by a move operation, that is, the given graph becomes empty. Returns iterator to the top node.

Definition at line 2059 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, tim::tgraph_node< T >::next_sibling, tim::graph< T, AllocatorT >::iterator_base::node, tim::tgraph_node< T >::parent, and tim::tgraph_node< T >::prev_sibling.

◆ move_in_as_nth_child()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::move_in_as_nth_child ( IterT  loc,
size_t  n,
graph< T, AllocatorT > &  other 
)
inline

As above, but now make the graph the nth child of the indicated node (if possible).

Definition at line 2097 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, tim::tgraph_node< T >::first_child, tim::graph< T, AllocatorT >::head, tim::tgraph_node< T >::last_child, tim::tgraph_node< T >::next_sibling, tim::tgraph_node< T >::parent, and tim::tgraph_node< T >::prev_sibling.

◆ move_in_below()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::move_in_below ( IterT  ,
graph< T, AllocatorT > &   
)
inline

As above, but now make the graph a child of the indicated node.

◆ move_ontop()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::move_ontop ( IterT  target,
IterT  source 
)
inline

Move 'source' node (plus its children) to become the node at 'target' (erasing the node at 'target').

Definition at line 1964 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::erase(), tim::tgraph_node< T >::first_child, tim::tgraph_node< T >::last_child, tim::tgraph_node< T >::next_sibling, tim::tgraph_node< T >::parent, and tim::tgraph_node< T >::prev_sibling.

Referenced by tim::graph< T, AllocatorT >::append_child(), and tim::graph< T, AllocatorT >::prepend_child().

◆ move_out()

template<typename T , typename AllocatorT >
graph< T, AllocatorT > tim::graph< T, AllocatorT >::move_out ( iterator  source)
inline

Extract the subgraph starting at the indicated node, removing it from the original graph.

Definition at line 2031 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, tim::tgraph_node< T >::next_sibling, tim::graph< T, AllocatorT >::iterator_base::node, tim::tgraph_node< T >::parent, and tim::tgraph_node< T >::prev_sibling.

◆ next_sibling()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::next_sibling ( IterT  position)
static

Return iterator to the next sibling of a node.

Definition at line 1065 of file graph.hpp.

1066 {
1067  assert(position.node != nullptr);
1068  IterT ret(position);
1069  ret.node = position.node->next_sibling;
1070  return ret;
1071 }

◆ number_of_children()

template<typename T , typename AllocatorT >
unsigned int tim::graph< T, AllocatorT >::number_of_children ( const iterator_base it)
static

Count the number of children of node at position.

Definition at line 2461 of file graph.hpp.

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 }

References tim::tgraph_node< T >::first_child, tim::graph< T, AllocatorT >::iterator_base::node, and tim::pos.

Referenced by tim::print_subgraph(), tim::print_subgraph_bracketed(), and tim::print_subgraph_hierarchy().

◆ number_of_siblings()

template<typename T , typename AllocatorT >
unsigned int tim::graph< T, AllocatorT >::number_of_siblings ( const iterator_base it) const
inline

Count the number of siblings (left and right) of node at iterator. Total nodes at this level is +1.

Definition at line 2477 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, tim::graph< T, AllocatorT >::iterator_base::node, and tim::pos.

Referenced by tim::graph< T, AllocatorT >::merge(), tim::print_graph(), tim::print_graph_bracketed(), tim::print_graph_hierarchy(), tim::print_subgraph(), tim::print_subgraph_bracketed(), tim::print_subgraph_hierarchy(), and tim::graph< T, AllocatorT >::reduce().

◆ operator=() [1/2]

template<typename T , typename AllocatorT >
graph< T, AllocatorT > & tim::graph< T, AllocatorT >::operator= ( const graph< T, AllocatorT > &  other)

Definition at line 857 of file graph.hpp.

858 {
859  if(this != &other)
860  m_copy(other);
861  return *this;
862 }

◆ operator=() [2/2]

template<typename T , typename AllocatorT >
graph< T, AllocatorT > & tim::graph< T, AllocatorT >::operator= ( graph< T, AllocatorT > &&  x)
noexcept

Definition at line 868 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, tim::tgraph_node< T >::next_sibling, and tim::tgraph_node< T >::prev_sibling.

◆ parent()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::parent ( IterT  position)
static

Return iterator to the parent of a node.

Definition at line 1041 of file graph.hpp.

1042 {
1043  assert(position.node != nullptr);
1044  return IterT(position.node->parent);
1045 }

Referenced by tim::graph< T, AllocatorT >::merge().

◆ prepend_child() [1/4]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::prepend_child ( IterT  position)
inline

Definition at line 1109 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, and tim::graph< T, AllocatorT >::head.

Referenced by tim::graph< T, AllocatorT >::prepend_child().

◆ prepend_child() [2/4]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::prepend_child ( IterT  position,
const T &  x 
)
inline

Definition at line 1207 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, and tim::graph< T, AllocatorT >::head.

◆ prepend_child() [3/4]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::prepend_child ( IterT  position,
IterT  other_position 
)
inline

Definition at line 1285 of file graph.hpp.

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 }
IterT prepend_child(IterT position)
Definition: graph.hpp:1109

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, tim::graph< T, AllocatorT >::move_ontop(), and tim::graph< T, AllocatorT >::prepend_child().

◆ prepend_child() [4/4]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::prepend_child ( IterT  position,
T &&  x 
)
inline

Definition at line 1238 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, and tim::graph< T, AllocatorT >::head.

◆ prepend_children()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::prepend_children ( IterT  position,
sibling_iterator  from,
sibling_iterator  to 
)
inline

Definition at line 1322 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, and tim::graph< T, AllocatorT >::insert_subgraph().

◆ previous_sibling()

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::previous_sibling ( IterT  position)
static

Return iterator to the previous sibling of a node.

Definition at line 1052 of file graph.hpp.

1053 {
1054  assert(position.node != nullptr);
1055  IterT ret(position);
1056  ret.node = position.node->prev_sibling;
1057  return ret;
1058 }

◆ reduce()

template<typename T , typename AllocatorT >
template<typename ComparePred , typename ReducePred >
void tim::graph< T, AllocatorT >::reduce ( const sibling_iterator lhs,
const sibling_iterator ,
std::set< sibling_iterator > &  _erase,
ComparePred &&  _compare = [](sibling_iterator lhs,                           sibling_iterator rhs) { return (*lhs == *rhs); },
ReducePred &&  _reduce = [](sibling_iterator lhs, sibling_iterator rhs) { *lhs += *rhs; } 
)
inline

Reduce duplicate nodes.

Definition at line 2229 of file graph.hpp.

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 }
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
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
sibling_iterator sibling(const iterator_base &position, unsigned int) const
Return iterator to the sibling indicated by index.
Definition: graph.hpp:2658
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

References tim::graph< T, AllocatorT >::erase(), tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::index(), tim::graph< T, AllocatorT >::insert_subgraph_after(), tim::graph< T, AllocatorT >::is_valid(), tim::graph< T, AllocatorT >::iterator_base::node, tim::graph< T, AllocatorT >::number_of_siblings(), and tim::graph< T, AllocatorT >::sibling().

◆ reparent() [1/2]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::reparent ( IterT  position,
IterT  from 
)
inline

Move all child nodes of 'from' to be children of 'position'.

Definition at line 1815 of file graph.hpp.

1816 {
1817  if(from.node->first_child == nullptr)
1818  return position;
1819  return reparent(position, from.node->first_child, end(from));
1820 }
IterT reparent(IterT position, sibling_iterator begin, const sibling_iterator &end)
Move nodes in range to be children of 'position'.
Definition: graph.hpp:1752

References tim::graph< T, AllocatorT >::iterator_base::end(), and tim::graph< T, AllocatorT >::reparent().

◆ reparent() [2/2]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::reparent ( IterT  position,
sibling_iterator  begin,
const sibling_iterator end 
)
inline

Move nodes in range to be children of 'position'.

Definition at line 1752 of file graph.hpp.

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 }

References tim::tgraph_node< T >::last_child, tim::tgraph_node< T >::next_sibling, tim::graph< T, AllocatorT >::iterator_base::node, tim::tgraph_node< T >::parent, tim::pos, and tim::tgraph_node< T >::prev_sibling.

Referenced by tim::graph< T, AllocatorT >::reparent(), and tim::graph< T, AllocatorT >::wrap().

◆ replace() [1/4]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::replace ( IterT  position,
const iterator_base from 
)
inline

Replace node at 'position' with subgraph starting at 'from' (do not erase subgraph at 'from'); see above.

Definition at line 1592 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::erase_children(), tim::graph< T, AllocatorT >::head, and tim::graph< T, AllocatorT >::iterator_base::node.

◆ replace() [2/4]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::replace ( IterT  position,
const T &  x 
)
inline

Replace node at 'position' with other node (keeping same children); 'position' becomes invalid.

Definition at line 1568 of file graph.hpp.

1569 {
1570  allocator_traits::destroy(m_alloc, position.node);
1571  allocator_traits::construct(m_alloc, position.node, x);
1572  return position;
1573 }

References tim::invoke::destroy().

Referenced by tim::graph< T, AllocatorT >::graph(), tim::graph< T, AllocatorT >::insert_subgraph(), and tim::graph< T, AllocatorT >::insert_subgraph_after().

◆ replace() [3/4]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::replace ( IterT  position,
T &&  x 
)
inline

Definition at line 1580 of file graph.hpp.

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 }

References tim::invoke::destroy().

◆ replace() [4/4]

template<typename T , typename AllocatorT >
graph< T, AllocatorT >::sibling_iterator tim::graph< T, AllocatorT >::replace ( sibling_iterator  orig_begin,
const sibling_iterator orig_end,
sibling_iterator  new_begin,
const sibling_iterator new_end 
)
inline

Replace string of siblings (plus their children) with copy of a new string (with children); see above.

Definition at line 1668 of file graph.hpp.

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  {
1686  pre_order_iterator tt = insert_subgraph(pre_order_iterator(orig_first),
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 }

References tim::graph< T, AllocatorT >::pre_order_iterator::pre_order_iterator(), tim::graph< T, AllocatorT >::erase(), tim::graph< T, AllocatorT >::insert_subgraph(), tim::tgraph_node< T >::next_sibling, and tim::graph< T, AllocatorT >::iterator_base::node.

◆ serialize()

template<typename T , typename AllocatorT >
template<typename Archive >
void tim::graph< T, AllocatorT >::serialize ( Archive &  ar,
const unsigned int   
)
inline

Definition at line 755 of file graph.hpp.

756  {
757  for(auto itr = begin(); itr != end(); ++itr)
758  ar(cereal::make_nvp("node", *itr));
759  }

References tim::graph< T, AllocatorT >::iterator_base::begin(), and tim::graph< T, AllocatorT >::iterator_base::end().

◆ set_head() [1/2]

template<typename T , typename AllocatorT >
graph< T, AllocatorT >::pre_order_iterator tim::graph< T, AllocatorT >::set_head ( const T &  x)
inline

Short-hand to insert topmost node in otherwise empty graph.

Definition at line 1346 of file graph.hpp.

1347 {
1348  assert(head->next_sibling == feet);
1349  return insert(iterator(feet), x);
1350 }
pre_order_iterator iterator
The default iterator types throughout the graph class.
Definition: graph.hpp:438

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, tim::graph< T, AllocatorT >::insert(), and tim::tgraph_node< T >::next_sibling.

Referenced by tim::graph< T, AllocatorT >::graph(), and tim::graph_data< NodeT >::graph_data().

◆ set_head() [2/2]

template<typename T , typename AllocatorT >
graph< T, AllocatorT >::pre_order_iterator tim::graph< T, AllocatorT >::set_head ( T &&  x)
inline

Definition at line 1356 of file graph.hpp.

1357 {
1358  assert(head->next_sibling == feet);
1359  return insert(iterator(feet), std::move(x));
1360 }

References tim::graph< T, AllocatorT >::feet, tim::graph< T, AllocatorT >::head, tim::graph< T, AllocatorT >::insert(), and tim::tgraph_node< T >::next_sibling.

◆ sibling()

template<typename T , typename AllocatorT >
graph< T, AllocatorT >::sibling_iterator tim::graph< T, AllocatorT >::sibling ( const iterator_base position,
unsigned int  num 
) const
inline

Return iterator to the sibling indicated by index.

Definition at line 2658 of file graph.hpp.

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 }

References tim::tgraph_node< T >::next_sibling, tim::graph< T, AllocatorT >::iterator_base::node, tim::tgraph_node< T >::parent, and tim::tgraph_node< T >::prev_sibling.

Referenced by tim::graph< T, AllocatorT >::reduce().

◆ size()

template<typename T , typename AllocatorT >
size_t tim::graph< T, AllocatorT >::size
inline

Count the total number of nodes.

Definition at line 3157 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::begin(), and tim::graph< T, AllocatorT >::end().

◆ subgraph() [1/2]

template<typename T , typename AllocatorT >
void tim::graph< T, AllocatorT >::subgraph ( graph< T, AllocatorT > &  ,
sibling_iterator  from,
sibling_iterator  to 
) const
inline

◆ subgraph() [2/2]

template<typename T , typename AllocatorT >
graph tim::graph< T, AllocatorT >::subgraph ( sibling_iterator  from,
sibling_iterator  to 
) const
inline

Extract a new graph formed by the range of siblings plus all their children.

◆ swap() [1/2]

template<typename T , typename AllocatorT >
void tim::graph< T, AllocatorT >::swap ( iterator  one,
iterator  two 
)
inline

Exchange two nodes (plus subgraphs). The iterators will remain valid and keep pointing to the same nodes, which now sit at different locations in the graph.

Definition at line 2535 of file graph.hpp.

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 }
void swap(sibling_iterator it)
Exchange the node (plus subgraph) with its sibling node (do nothing if no sibling present).
Definition: graph.hpp:2502

References tim::tgraph_node< T >::first_child, tim::tgraph_node< T >::last_child, tim::tgraph_node< T >::next_sibling, tim::graph< T, AllocatorT >::iterator_base::node, tim::tgraph_node< T >::parent, tim::tgraph_node< T >::prev_sibling, and tim::graph< T, AllocatorT >::swap().

◆ swap() [2/2]

template<typename T , typename AllocatorT >
void tim::graph< T, AllocatorT >::swap ( sibling_iterator  it)
inline

Exchange the node (plus subgraph) with its sibling node (do nothing if no sibling present).

Definition at line 2502 of file graph.hpp.

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 }

References tim::tgraph_node< T >::next_sibling, tim::graph< T, AllocatorT >::iterator_base::node, tim::tgraph_node< T >::parent, and tim::tgraph_node< T >::prev_sibling.

Referenced by tim::graph< T, AllocatorT >::swap().

◆ wrap() [1/2]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::wrap ( IterT  from,
IterT  to,
const T &  x 
)
inline

Replace the range of sibling nodes (plus subgraphs), making these children of the new node.

Definition at line 1843 of file graph.hpp.

1844 {
1845  assert(from.node != nullptr);
1846  IterT ret = insert(from, x);
1847  reparent(ret, from, to);
1848  return ret;
1849 }

References tim::graph< T, AllocatorT >::insert(), and tim::graph< T, AllocatorT >::reparent().

◆ wrap() [2/2]

template<typename T , typename AllocatorT >
template<typename IterT >
IterT tim::graph< T, AllocatorT >::wrap ( IterT  position,
const T &  x 
)
inline

Replace node with a new node, making the old node (plus subgraph) a child of the new node.

Definition at line 1827 of file graph.hpp.

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 }

References tim::graph< T, AllocatorT >::insert(), and tim::graph< T, AllocatorT >::reparent().

Member Data Documentation

◆ feet

◆ head


The documentation for this class was generated from the following file: