timemory 3.3.0
Modular C++ Toolkit for Performance Analysis and Logging. Profiling API and Tools for C, C++, CUDA, Fortran, and Python. The C++ template API is essentially a framework to creating tools: it is designed to provide a unifying interface for recording various performance measurements alongside data logging and interfaces to other tools.
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 ()
 
 graph (const this_type &)=delete
 
 graph (this_type &&) noexcept=default
 
graphoperator= (const graph &)=delete
 
graphoperator= (graph &&) noexcept=default
 
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)
 
void steal_resources (this_type &rhs)
 

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 = nullptr
 
graph_nodefeet = nullptr
 

Protected Types

using graph_node = tgraph_node< T >
 
using this_type = graph< T, AllocatorT >
 

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 114 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 219 of file graph.hpp.

◆ difference_type

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

Definition at line 220 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 117 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 218 of file graph.hpp.

◆ this_type

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

Definition at line 118 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 122 of file graph.hpp.

Constructor & Destructor Documentation

◆ graph() [1/5]

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

Definition at line 556 of file graph.hpp.

557{
558 m_head_initialize();
559}

◆ graph() [2/5]

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

Definition at line 564 of file graph.hpp.

565{
566 m_head_initialize();
567 set_head(x);
568}
pre_order_iterator set_head(const T &x)
Short-hand to insert topmost node in otherwise empty graph.
Definition: graph.hpp:1057

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 573 of file graph.hpp.

574{
575 m_head_initialize();
576 set_head((*other));
577 replace(begin(), other);
578}
IterT replace(IterT position, const T &x)
Replace node at 'position' with other node (keeping same children); 'position' becomes invalid.
Definition: graph.hpp:1279
pre_order_iterator begin() const
Return iterator to the beginning of the graph.
Definition: graph.hpp:708

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

◆ ~graph()

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

Definition at line 583 of file graph.hpp.

584{
585 clear();
586 if(m_alloc)
587 {
590 allocator_traits::deallocate(*m_alloc, head, 1);
591 allocator_traits::deallocate(*m_alloc, feet, 1);
592 }
593 while(!m_stolen_alloc.empty())
594 {
595 auto _v = m_stolen_alloc.back();
596 m_stolen_alloc.pop_back();
598 }
600}
graph_node * feet
Definition: graph.hpp:539
void clear()
Erase all nodes of the graph.
Definition: graph.hpp:631
graph_node * head
Definition: graph.hpp:538
auto destroy(TupleT< Tp... > &obj)
Definition: functional.cpp:282
static auto release(std::shared_ptr< AllocT > &_v)

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

◆ graph() [4/5]

template<typename T , typename AllocatorT >
tim::graph< T, AllocatorT >::graph ( const this_type )
delete

◆ graph() [5/5]

template<typename T , typename AllocatorT >
tim::graph< T, AllocatorT >::graph ( this_type &&  )
defaultnoexcept

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 789 of file graph.hpp.

790{
791 assert(position.node != head);
792 assert(position.node != feet);
793 assert(position.node);
794
795 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
796 allocator_traits::construct(*m_alloc, tmp, std::move(tgraph_node<T>{}));
797 tmp->first_child = nullptr;
798 tmp->last_child = nullptr;
799
800 tmp->parent = position.node;
801 if(position.node->last_child != nullptr)
802 {
803 position.node->last_child->next_sibling = tmp;
804 }
805 else
806 {
807 position.node->first_child = tmp;
808 }
809 tmp->prev_sibling = position.node->last_child;
810 position.node->last_child = tmp;
811 tmp->next_sibling = nullptr;
812 return tmp;
813}
tgraph_node< T > graph_node
Definition: graph.hpp:117

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 851 of file graph.hpp.

852{
853 // If your program fails here you probably used 'append_child' to add the
854 // top node to an empty graph. From version 1.45 the top element should be
855 // added using 'insert'. See the documentation for further information, and
856 // sorry about the API change.
857 assert(position.node != head);
858 assert(position.node != feet);
859 assert(position.node);
860
861 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
862 allocator_traits::construct(*m_alloc, tmp, x);
863 tmp->first_child = nullptr;
864 tmp->last_child = nullptr;
865
866 tmp->parent = position.node;
867 if(position.node->last_child != nullptr)
868 {
869 position.node->last_child->next_sibling = tmp;
870 }
871 else
872 {
873 position.node->first_child = tmp;
874 }
875 tmp->prev_sibling = position.node->last_child;
876 position.node->last_child = tmp;
877 tmp->next_sibling = nullptr;
878 return tmp;
879}

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 981 of file graph.hpp.

982{
983 assert(position.node != head);
984 assert(position.node != feet);
985 assert(position.node);
986
987 IterT aargh = append_child(position, value_type{});
988 return move_ontop(aargh, other);
989}
IterT append_child(IterT position)
Insert empty node as last/first child of node pointed to by position.
Definition: graph.hpp:789
IterT move_ontop(IterT target, IterT source)
Move 'source' node (plus its children) to become the node at 'target' (erasing the node at 'target').
Definition: graph.hpp:1675
T value_type
Value of the data stored at a node.
Definition: graph.hpp:122

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 886 of file graph.hpp.

887{
888 assert(position.node != head);
889 assert(position.node != feet);
890 assert(position.node);
891
892 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
893 allocator_traits::construct(*m_alloc, tmp, std::forward<T>(x));
894
895 tmp->first_child = nullptr;
896 tmp->last_child = nullptr;
897
898 tmp->parent = position.node;
899 if(position.node->last_child != nullptr)
900 {
901 position.node->last_child->next_sibling = tmp;
902 }
903 else
904 {
905 position.node->first_child = tmp;
906 }
907 tmp->prev_sibling = position.node->last_child;
908 position.node->last_child = tmp;
909 tmp->next_sibling = nullptr;
910 return tmp;
911}

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 1011 of file graph.hpp.

1013{
1014 assert(position.node != head);
1015 assert(position.node != feet);
1016 assert(position.node);
1017
1018 IterT ret = from;
1019
1020 while(from != to)
1021 {
1022 insert_subgraph(position.end(), from);
1023 ++from;
1024 }
1025 return ret;
1026}
IterT insert_subgraph(IterT position, const iterator_base &subgraph)
Insert node (with children) pointed to by subgraph as previous sibling of node pointed to by position...
Definition: graph.hpp:1239

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 726 of file graph.hpp.

727{
728 assert(pos.node != nullptr);
729 if(pos.node->first_child == nullptr)
730 {
731 return end(pos);
732 }
733 return pos.node->first_child;
734}
pre_order_iterator end() const
Return iterator to the end of the graph.
Definition: graph.hpp:717
size_t pos
Definition: config.cpp:102

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 2397 of file graph.hpp.

2398{
2399 graph_node* tmp = it.node->first_child;
2400 while((num--) != 0u)
2401 {
2402 assert(tmp != nullptr);
2403 tmp = tmp->next_sibling;
2404 }
2405 return tmp;
2406}

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 631 of file graph.hpp.

632{
633 if(head)
634 {
635 while(head->next_sibling != feet)
636 erase(pre_order_iterator(head->next_sibling));
637 }
638}
IterT erase(IterT)
Erase element at position pointed to by iterator, return incremented iterator.
Definition: graph.hpp:666

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 2085 of file graph.hpp.

2086{
2087 graph_node* pos = it.node;
2088 assert(pos != nullptr);
2089 int ret = 0;
2090 while(pos->parent != nullptr)
2091 {
2092 pos = pos->parent;
2093 ++ret;
2094 }
2095 return ret;
2096}

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 2102 of file graph.hpp.

2103{
2104 graph_node* pos = it.node;
2105 assert(pos != nullptr);
2106 int ret = 0;
2107 while(pos->parent != nullptr && pos != root.node)
2108 {
2109 pos = pos->parent;
2110 ++ret;
2111 }
2112 return ret;
2113}

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 2074 of file graph.hpp.

2075{
2076 pre_order_iterator it = begin();
2077 pre_order_iterator eit = end();
2078 return (it == eit);
2079}

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 740 of file graph.hpp.

741{
742 sibling_iterator ret(nullptr);
743 ret.m_parent = pos.node;
744 return ret;
745}

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 2009 of file graph.hpp.

2011{
2012 std::equal_to<T> comp;
2013 return equal(one_, two, three_, comp);
2014}
bool equal(const IterT &one, const IterT &two, const IterT &three) const
Compare two ranges of nodes (compares nodes as well as graph structure).
Definition: graph.hpp:2009

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

Referenced by tim::graph< T, AllocatorT >::equal(), and 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 2032 of file graph.hpp.

2034{
2035 pre_order_iterator one(one_);
2036 pre_order_iterator three(three_);
2037
2038 // if(one==two && is_valid(three) && three.number_of_children()!=0)
2039 // return false;
2040 while(one != two && is_valid(three))
2041 {
2042 if(!fun(*one, *three))
2043 return false;
2044 if(one.number_of_children() != three.number_of_children())
2045 return false;
2046 ++one;
2047 ++three;
2048 }
2049 return true;
2050}
bool is_valid(const iterator_base &) const
Determine whether the iterator is an 'end' iterator and thus not actually pointing to a node.
Definition: graph.hpp:2313

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 2021 of file graph.hpp.

2022{
2023 std::equal_to<T> comp;
2024 return equal_subgraph(one_, two_, comp);
2025}
bool equal_subgraph(const IterT &one, const IterT &two) const
Definition: graph.hpp:2021

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

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

◆ 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 2057 of file graph.hpp.

2059{
2060 pre_order_iterator one(one_);
2061 pre_order_iterator two(two_);
2062
2063 if(!fun(*one, *two))
2064 return false;
2065 if(number_of_children(one) != number_of_children(two))
2066 return false;
2067 return equal(begin(one), end(one), begin(two), fun);
2068}
static unsigned int number_of_children(const iterator_base &)
Count the number of children of node at position.
Definition: graph.hpp:2172

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 666 of file graph.hpp.

667{
668 graph_node* cur = it.node;
669 assert(cur != head);
670 assert(cur != feet);
671 if(cur == head || cur == feet)
672 return it;
673 IterT ret = it;
674 // ret.skip_children();
675 ++ret;
676 erase_children(it);
677 if(cur->parent && cur->prev_sibling == nullptr)
678 {
679 cur->parent->first_child = cur->next_sibling;
680 }
681 else
682 {
683 cur->prev_sibling->next_sibling = cur->next_sibling;
684 }
685
686 if(cur->parent && cur->next_sibling == nullptr)
687 {
688 cur->parent->last_child = cur->prev_sibling;
689 }
690 else
691 {
692 cur->next_sibling->prev_sibling = cur->prev_sibling;
693 }
694
695 if(m_alloc)
696 {
697 allocator_traits::destroy(*m_alloc, cur);
698 allocator_traits::deallocate(*m_alloc, cur, 1);
699 }
700 it.node = nullptr;
701 return ret;
702}
void erase_children(const iterator_base &)
Erase all children of the node pointed to by iterator.
Definition: graph.hpp:644

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 644 of file graph.hpp.

645{
646 if(it.node == nullptr)
647 return;
648
649 graph_node* cur = it.node->first_child;
650
651 if(cur)
652 {
653 while(cur->next_sibling && cur->next_sibling != feet)
654 erase(pre_order_iterator(cur->next_sibling));
655 }
656
657 it.node->first_child = nullptr;
658 it.node->last_child = nullptr;
659}

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 1430 of file graph.hpp.

1431{
1432 if(position.node->first_child == nullptr)
1433 return position;
1434
1435 graph_node* tmp = position.node->first_child;
1436 while(tmp)
1437 {
1438 tmp->parent = position.node->parent;
1439 tmp = tmp->next_sibling;
1440 }
1441 if(position.node->next_sibling)
1442 {
1443 position.node->last_child->next_sibling = position.node->next_sibling;
1444 position.node->next_sibling->prev_sibling = position.node->last_child;
1445 }
1446 else
1447 {
1448 position.node->parent->last_child = position.node->last_child;
1449 }
1450 position.node->next_sibling = position.node->first_child;
1451 position.node->next_sibling->prev_sibling = position.node;
1452 position.node->first_child = nullptr;
1453 position.node->last_child = nullptr;
1454
1455 return position;
1456}

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 2339 of file graph.hpp.

2340{
2341 graph_node* tmp = it.node;
2342 if(!tmp)
2343 return static_cast<unsigned int>(-1);
2344
2345 if(tmp->parent != nullptr)
2346 {
2347 tmp = tmp->parent->first_child;
2348 }
2349 else
2350 {
2351 while(tmp->prev_sibling != nullptr)
2352 tmp = tmp->prev_sibling;
2353 }
2354
2355 unsigned int ret = 0;
2356 while(tmp != it.node)
2357 {
2358 ++ret;
2359 tmp = tmp->next_sibling;
2360 }
2361
2362 return ret;
2363}

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 1078 of file graph.hpp.

1079{
1080 if(position.node == nullptr)
1081 {
1082 position.node = feet; // Backward compatibility: when calling insert on
1083 // a null node, insert before the feet.
1084 }
1085 assert(position.node != head); // Cannot insert before head.
1086
1087 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1088 allocator_traits::construct(*m_alloc, tmp, x);
1089 tmp->first_child = nullptr;
1090 tmp->last_child = nullptr;
1091
1092 tmp->parent = position.node->parent;
1093 tmp->next_sibling = position.node;
1094 tmp->prev_sibling = position.node->prev_sibling;
1095 position.node->prev_sibling = tmp;
1096
1097 if(tmp->prev_sibling == nullptr)
1098 {
1099 if(tmp->parent) // when inserting nodes at the head, there is no parent
1100 tmp->parent->first_child = tmp;
1101 }
1102 else
1103 tmp->prev_sibling->next_sibling = tmp;
1104 return tmp;
1105}

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 1112 of file graph.hpp.

1113{
1114 if(position.node == nullptr)
1115 {
1116 position.node = feet; // Backward compatibility: when calling insert on
1117 // a null node, insert before the feet.
1118 }
1119 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1120 allocator_traits::construct(*m_alloc, tmp, std::forward<T>(x));
1121
1122 tmp->first_child = nullptr;
1123 tmp->last_child = nullptr;
1124
1125 tmp->parent = position.node->parent;
1126 tmp->next_sibling = position.node;
1127 tmp->prev_sibling = position.node->prev_sibling;
1128 position.node->prev_sibling = tmp;
1129
1130 if(tmp->prev_sibling == nullptr)
1131 {
1132 if(tmp->parent) // when inserting nodes at the head, there is no parent
1133 tmp->parent->first_child = tmp;
1134 }
1135 else
1136 tmp->prev_sibling->next_sibling = tmp;
1137 return tmp;
1138}

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 1144 of file graph.hpp.

1145{
1146 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1147 allocator_traits::construct(*m_alloc, tmp, x);
1148 tmp->first_child = nullptr;
1149 tmp->last_child = nullptr;
1150
1151 tmp->next_sibling = position.node;
1152 if(position.node == nullptr)
1153 { // iterator points to end of a subgraph
1154 tmp->parent = position.m_parent;
1155 tmp->prev_sibling = position.range_last();
1156 tmp->parent->last_child = tmp;
1157 }
1158 else
1159 {
1160 tmp->parent = position.node->parent;
1161 tmp->prev_sibling = position.node->prev_sibling;
1162 position.node->prev_sibling = tmp;
1163 }
1164
1165 if(tmp->prev_sibling == nullptr)
1166 {
1167 if(tmp->parent) // when inserting nodes at the head, there is no parent
1168 tmp->parent->first_child = tmp;
1169 }
1170 else
1171 tmp->prev_sibling->next_sibling = tmp;
1172 return tmp;
1173}

◆ 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 1180 of file graph.hpp.

1181{
1182 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1183 allocator_traits::construct(*m_alloc, tmp, x);
1184 tmp->first_child = nullptr;
1185 tmp->last_child = nullptr;
1186
1187 tmp->parent = position.node->parent;
1188 tmp->prev_sibling = position.node;
1189 tmp->next_sibling = position.node->next_sibling;
1190 position.node->next_sibling = tmp;
1191
1192 if(tmp->next_sibling == nullptr)
1193 {
1194 if(tmp->parent) // when inserting nodes at the head, there is no parent
1195 tmp->parent->last_child = tmp;
1196 }
1197 else
1198 {
1199 tmp->next_sibling->prev_sibling = tmp;
1200 }
1201 return tmp;
1202}

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 1209 of file graph.hpp.

1210{
1211 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1212 allocator_traits::construct(*m_alloc, tmp, std::forward<T>(x));
1213
1214 tmp->first_child = nullptr;
1215 tmp->last_child = nullptr;
1216
1217 tmp->parent = position.node->parent;
1218 tmp->prev_sibling = position.node;
1219 tmp->next_sibling = position.node->next_sibling;
1220 position.node->next_sibling = tmp;
1221
1222 if(tmp->next_sibling == nullptr)
1223 {
1224 if(tmp->parent) // when inserting nodes at the head, there is no parent
1225 tmp->parent->last_child = tmp;
1226 }
1227 else
1228 {
1229 tmp->next_sibling->prev_sibling = tmp;
1230 }
1231 return tmp;
1232}

◆ 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 1239 of file graph.hpp.

1240{
1241 // insert dummy
1242 IterT it = insert(position, value_type{});
1243 // replace dummy with subgraph
1244 return replace(it, _subgraph);
1245}
IterT insert(IterT position, const T &x)
Insert node as previous sibling of node pointed to by position.
Definition: graph.hpp:1078

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 1252 of file graph.hpp.

1254{
1255 // insert dummy
1256 IterT it = insert_after(position, value_type{});
1257 // replace dummy with subgraph
1258 return replace(it, _subgraph);
1259}
IterT insert_after(IterT position, const T &x)
Insert node as next sibling of node pointed to by position.
Definition: graph.hpp:1180

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 2328 of file graph.hpp.

2329{
2330 if(it.node->parent == nullptr)
2331 return true;
2332 return false;
2333}

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 2313 of file graph.hpp.

2314{
2315 if(it.node == nullptr || it.node == feet || it.node == head)
2316 {
2317 return false;
2318 }
2319 {
2320 return true;
2321 }
2322}

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 2119 of file graph.hpp.

2120{
2121 int maxd = -1;
2122 for(graph_node* it = head->next_sibling; it != feet; it = it->next_sibling)
2123 maxd = std::max(maxd, max_depth(it));
2124
2125 return maxd;
2126}
int max_depth() const
Determine the maximal depth of the graph. An empty graph has max_depth=-1.
Definition: graph.hpp:2119
::tim::statistics< Tp > max(::tim::statistics< Tp > lhs, const Tp &rhs)
Definition: statistics.hpp:320

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

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

◆ 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 2132 of file graph.hpp.

2133{
2134 graph_node* tmp = pos.node;
2135
2136 if(tmp == nullptr || tmp == head || tmp == feet)
2137 return -1;
2138
2139 int curdepth = 0;
2140 int maxdepth = 0;
2141 while(true)
2142 { // try to walk the bottom of the graph
2143 while(tmp->first_child == nullptr)
2144 {
2145 if(tmp == pos.node)
2146 return maxdepth;
2147 if(tmp->next_sibling == nullptr)
2148 {
2149 // try to walk up and then right again
2150 do
2151 {
2152 tmp = tmp->parent;
2153 if(tmp == nullptr)
2154 return maxdepth;
2155 --curdepth;
2156 } while(tmp->next_sibling == nullptr);
2157 }
2158 if(tmp == pos.node)
2159 return maxdepth;
2160 tmp = tmp->next_sibling;
2161 }
2162 tmp = tmp->first_child;
2163 ++curdepth;
2164 maxdepth = std::max(curdepth, maxdepth);
2165 }
2166}

References tim::graph< T, AllocatorT >::feet, tim::tgraph_node< T >::first_child, tim::graph< T, AllocatorT >::head, std::max(), 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 1883 of file graph.hpp.

1886{
1887 while(from1 != from2)
1888 {
1889 sibling_iterator fnd;
1890 auto nsiblings = number_of_siblings(to1);
1891 decltype(nsiblings) count = nullptr;
1892 for(sibling_iterator itr = to1; itr != to2; ++itr, ++count)
1893 {
1894 if(itr && from1 && *itr == *from1)
1895 {
1896 fnd = itr;
1897 break;
1898 }
1899 if(count > nsiblings)
1900 {
1901 fnd = to2;
1902 break;
1903 }
1904 }
1905 // auto fnd = std::find(to1, to2, *from1);
1906 if(fnd != to2) // element found
1907 {
1908 if(from1.begin() == from1.end()) // full depth reached
1909 {
1910 if(duplicate_leaves)
1911 append_child(parent(to1), (*from1));
1912 }
1913 else // descend further
1914 {
1915 if(!first)
1916 *fnd += *from1;
1917 if(from1 != from2)
1918 {
1919 merge(fnd.begin(), fnd.end(), from1.begin(), from1.end(),
1920 duplicate_leaves);
1921 }
1922 }
1923 }
1924 else
1925 { // element missing
1926 insert_subgraph(to2, from1);
1927 }
1928 do
1929 {
1930 ++from1;
1931 } while(!from1 && from1 != from2);
1932 }
1933}
void merge(const sibling_iterator &, const sibling_iterator &, sibling_iterator, const sibling_iterator &, bool duplicate_leaves=false, bool first=false)
Merge with other graph, creating new branches and leaves only if they are not already present.
Definition: graph.hpp:1883
static IterT parent(IterT)
Return iterator to the parent of a node.
Definition: graph.hpp:752
unsigned int number_of_siblings(const iterator_base &) const
Count the number of siblings (left and right) of node at iterator. Total nodes at this level is +1.
Definition: graph.hpp:2188

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 >::merge(), tim::graph< T, AllocatorT >::number_of_siblings(), and tim::graph< T, AllocatorT >::parent().

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

◆ 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 1567 of file graph.hpp.

1568{
1569 graph_node* dst = target.node;
1570 graph_node* src = source.node;
1571 assert(dst);
1572 assert(src);
1573
1574 if(dst == src)
1575 return source;
1576 if(dst->next_sibling)
1577 {
1578 if(dst->next_sibling == src) // already in the right spot
1579 return source;
1580 }
1581
1582 // take src out of the graph
1583 if(src->prev_sibling != nullptr)
1584 {
1585 src->prev_sibling->next_sibling = src->next_sibling;
1586 }
1587 else
1588 {
1589 src->parent->first_child = src->next_sibling;
1590 }
1591 if(src->next_sibling != nullptr)
1592 {
1593 src->next_sibling->prev_sibling = src->prev_sibling;
1594 }
1595 else
1596 {
1597 src->parent->last_child = src->prev_sibling;
1598 }
1599
1600 // connect it to the new point
1601 if(dst->next_sibling != nullptr)
1602 {
1603 dst->next_sibling->prev_sibling = src;
1604 }
1605 else
1606 {
1607 dst->parent->last_child = src;
1608 }
1609 src->next_sibling = dst->next_sibling;
1610 dst->next_sibling = src;
1611 src->prev_sibling = dst;
1612 src->parent = dst->parent;
1613 return src;
1614}

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 1621 of file graph.hpp.

1622{
1623 graph_node* dst = target.node;
1624 graph_node* src = source.node;
1625 assert(dst);
1626 assert(src);
1627
1628 if(dst == src)
1629 return source;
1630 if(dst->prev_sibling)
1631 {
1632 if(dst->prev_sibling == src) // already in the right spot
1633 return source;
1634 }
1635
1636 // take src out of the graph
1637 if(src->prev_sibling != nullptr)
1638 {
1639 src->prev_sibling->next_sibling = src->next_sibling;
1640 }
1641 else
1642 {
1643 src->parent->first_child = src->next_sibling;
1644 }
1645 if(src->next_sibling != nullptr)
1646 {
1647 src->next_sibling->prev_sibling = src->prev_sibling;
1648 }
1649 else
1650 {
1651 src->parent->last_child = src->prev_sibling;
1652 }
1653
1654 // connect it to the new point
1655 if(dst->prev_sibling != nullptr)
1656 {
1657 dst->prev_sibling->next_sibling = src;
1658 }
1659 else
1660 {
1661 dst->parent->first_child = src;
1662 }
1663 src->prev_sibling = dst->prev_sibling;
1664 dst->prev_sibling = src;
1665 src->next_sibling = dst;
1666 src->parent = dst->parent;
1667 return src;
1668}

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 1770 of file graph.hpp.

1771{
1772 if(other.head->next_sibling == other.feet)
1773 return loc; // other graph is empty
1774
1775 graph_node* other_first_head = other.head->next_sibling;
1776 graph_node* other_last_head = other.feet->prev_sibling;
1777
1778 sibling_iterator prev(loc);
1779 --prev;
1780
1781 prev.node->next_sibling = other_first_head;
1782 loc.node->prev_sibling = other_last_head;
1783 other_first_head->prev_sibling = prev.node;
1784 other_last_head->next_sibling = loc.node;
1785
1786 // Adjust parent pointers.
1787 graph_node* walk = other_first_head;
1788 while(true)
1789 {
1790 walk->parent = loc.node->parent;
1791 if(walk == other_last_head)
1792 break;
1793 walk = walk->next_sibling;
1794 }
1795
1796 // Close other graph.
1797 other.head->next_sibling = other.feet;
1798 other.feet->prev_sibling = other.head;
1799
1800 return other_first_head;
1801}

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 1808 of file graph.hpp.

1809{
1810 if(other.head->next_sibling == other.feet)
1811 return loc; // other graph is empty
1812
1813 graph_node* other_first_head = other.head->next_sibling;
1814 graph_node* other_last_head = other.feet->prev_sibling;
1815
1816 if(n == 0)
1817 {
1818 if(loc.node->first_child == nullptr)
1819 {
1820 loc.node->first_child = other_first_head;
1821 loc.node->last_child = other_last_head;
1822 other_last_head->next_sibling = nullptr;
1823 other_first_head->prev_sibling = nullptr;
1824 }
1825 else
1826 {
1827 loc.node->first_child->prev_sibling = other_last_head;
1828 other_last_head->next_sibling = loc.node->first_child;
1829 loc.node->first_child = other_first_head;
1830 other_first_head->prev_sibling = nullptr;
1831 }
1832 }
1833 else
1834 {
1835 --n;
1836 graph_node* walk = loc.node->first_child;
1837 while(true)
1838 {
1839 if(walk == nullptr)
1840 {
1841 throw std::range_error(
1842 "graph: move_in_as_nth_child position out of range");
1843 }
1844 if(n == 0)
1845 break;
1846 --n;
1847 walk = walk->next_sibling;
1848 }
1849 if(walk->next_sibling == nullptr)
1850 {
1851 loc.node->last_child = other_last_head;
1852 }
1853 else
1854 {
1855 walk->next_sibling->prev_sibling = other_last_head;
1856 }
1857 other_last_head->next_sibling = walk->next_sibling;
1858 walk->next_sibling = other_first_head;
1859 other_first_head->prev_sibling = walk;
1860 }
1861
1862 // Adjust parent pointers.
1863 graph_node* walk = other_first_head;
1864 while(true)
1865 {
1866 walk->parent = loc.node;
1867 if(walk == other_last_head)
1868 break;
1869 walk = walk->next_sibling;
1870 }
1871
1872 // Close other graph.
1873 other.head->next_sibling = other.feet;
1874 other.feet->prev_sibling = other.head;
1875
1876 return other_first_head;
1877}

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 1675 of file graph.hpp.

1676{
1677 graph_node* dst = target.node;
1678 graph_node* src = source.node;
1679 assert(dst);
1680 assert(src);
1681
1682 if(dst == src)
1683 return source;
1684
1685 // if(dst==src->prev_sibling) {
1686 //
1687 // }
1688
1689 // remember connection points
1690 graph_node* b_prev_sibling = dst->prev_sibling;
1691 graph_node* b_next_sibling = dst->next_sibling;
1692 graph_node* b_parent = dst->parent;
1693
1694 // remove target
1695 erase(target);
1696
1697 // take src out of the graph
1698 if(src->prev_sibling != nullptr)
1699 {
1700 src->prev_sibling->next_sibling = src->next_sibling;
1701 }
1702 else
1703 {
1704 src->parent->first_child = src->next_sibling;
1705 }
1706 if(src->next_sibling != nullptr)
1707 {
1708 src->next_sibling->prev_sibling = src->prev_sibling;
1709 }
1710 else
1711 {
1712 src->parent->last_child = src->prev_sibling;
1713 }
1714
1715 // connect it to the new point
1716 if(b_prev_sibling != nullptr)
1717 {
1718 b_prev_sibling->next_sibling = src;
1719 }
1720 else
1721 {
1722 b_parent->first_child = src;
1723 }
1724 if(b_next_sibling != nullptr)
1725 {
1726 b_next_sibling->prev_sibling = src;
1727 }
1728 else
1729 {
1730 b_parent->last_child = src;
1731 }
1732 src->prev_sibling = b_prev_sibling;
1733 src->next_sibling = b_next_sibling;
1734 src->parent = b_parent;
1735 return src;
1736}

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 1742 of file graph.hpp.

1743{
1744 graph ret;
1745
1746 // Move source node into the 'ret' graph.
1747 ret.head->next_sibling = source.node;
1748 ret.feet->prev_sibling = source.node;
1749 source.node->parent = nullptr;
1750
1751 // Close the links in the current graph.
1752 if(source.node->prev_sibling != nullptr)
1753 source.node->prev_sibling->next_sibling = source.node->next_sibling;
1754
1755 if(source.node->next_sibling != nullptr)
1756 source.node->next_sibling->prev_sibling = source.node->prev_sibling;
1757
1758 // Fix source prev/next links.
1759 source.node->prev_sibling = ret.head;
1760 source.node->next_sibling = ret.feet;
1761
1762 return ret; // A good compiler will move this, not copy.
1763}

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 776 of file graph.hpp.

777{
778 assert(position.node != nullptr);
779 IterT ret(position);
780 ret.node = position.node->next_sibling;
781 return ret;
782}

◆ 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 2172 of file graph.hpp.

2173{
2174 graph_node* pos = it.node->first_child;
2175 if(pos == nullptr)
2176 return 0;
2177
2178 unsigned int ret = 1;
2179 while((pos = pos->next_sibling))
2180 ++ret;
2181 return ret;
2182}

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 2188 of file graph.hpp.

2189{
2190 graph_node* pos = it.node;
2191 unsigned int ret = 0;
2192 // count forward
2193 while(pos->next_sibling && pos->next_sibling != head && pos->next_sibling != feet)
2194 {
2195 ++ret;
2196 pos = pos->next_sibling;
2197 }
2198 // count backward
2199 pos = it.node;
2200 while(pos->prev_sibling && pos->prev_sibling != head && pos->prev_sibling != feet)
2201 {
2202 ++ret;
2203 pos = pos->prev_sibling;
2204 }
2205
2206 return ret;
2207}

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 & tim::graph< T, AllocatorT >::operator= ( const graph< T, AllocatorT > &  )
delete

◆ operator=() [2/2]

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

◆ 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 752 of file graph.hpp.

753{
754 assert(position.node != nullptr);
755 return IterT(position.node->parent);
756}

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 820 of file graph.hpp.

821{
822 assert(position.node != head);
823 assert(position.node != feet);
824 assert(position.node);
825
826 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
827 allocator_traits::construct(*m_alloc, tmp, std::move(tgraph_node<T>{}));
828 tmp->first_child = nullptr;
829 tmp->last_child = nullptr;
830
831 tmp->parent = position.node;
832 if(position.node->first_child != nullptr)
833 {
834 position.node->first_child->prev_sibling = tmp;
835 }
836 else
837 {
838 position.node->last_child = tmp;
839 }
840 tmp->next_sibling = position.node->first_child;
841 position.node->prev_child = tmp;
842 tmp->prev_sibling = nullptr;
843 return tmp;
844}

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 918 of file graph.hpp.

919{
920 assert(position.node != head);
921 assert(position.node != feet);
922 assert(position.node);
923
924 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
925 allocator_traits::construct(*m_alloc, tmp, x);
926 tmp->first_child = nullptr;
927 tmp->last_child = nullptr;
928
929 tmp->parent = position.node;
930 if(position.node->first_child != nullptr)
931 {
932 position.node->first_child->prev_sibling = tmp;
933 }
934 else
935 {
936 position.node->last_child = tmp;
937 }
938 tmp->next_sibling = position.node->first_child;
939 position.node->first_child = tmp;
940 tmp->prev_sibling = nullptr;
941 return tmp;
942}

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 996 of file graph.hpp.

997{
998 assert(position.node != head);
999 assert(position.node != feet);
1000 assert(position.node);
1001
1002 IterT aargh = prepend_child(position, value_type{});
1003 return move_ontop(aargh, other);
1004}
IterT prepend_child(IterT position)
Definition: graph.hpp:820

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 949 of file graph.hpp.

950{
951 assert(position.node != head);
952 assert(position.node != feet);
953 assert(position.node);
954
955 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
956 allocator_traits::construct(*m_alloc, tmp, std::forward<T>(x));
957
958 tmp->first_child = nullptr;
959 tmp->last_child = nullptr;
960
961 tmp->parent = position.node;
962 if(position.node->first_child != nullptr)
963 {
964 position.node->first_child->prev_sibling = tmp;
965 }
966 else
967 {
968 position.node->last_child = tmp;
969 }
970 tmp->next_sibling = position.node->first_child;
971 position.node->first_child = tmp;
972 tmp->prev_sibling = nullptr;
973 return tmp;
974}

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 1033 of file graph.hpp.

1035{
1036 assert(position.node != head);
1037 assert(position.node != feet);
1038 assert(position.node);
1039
1040 if(from == to)
1041 return from; // should return end of graph?
1042
1043 IterT ret;
1044 do
1045 {
1046 --to;
1047 ret = insert_subgraph(position.begin(), to);
1048 } while(to != from);
1049
1050 return ret;
1051}

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 763 of file graph.hpp.

764{
765 assert(position.node != nullptr);
766 IterT ret(position);
767 ret.node = position.node->prev_sibling;
768 return ret;
769}

◆ 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 1940 of file graph.hpp.

1943{
1944 if(!is_valid(lhs))
1945 return;
1946
1947 for(pre_order_iterator litr = lhs; litr != feet; ++litr)
1948 {
1949 if(!litr)
1950 continue;
1951
1952 uint32_t nsiblings = number_of_siblings(litr);
1953 if(nsiblings < 2)
1954 continue;
1955
1956 uint32_t idx = index(litr);
1957 for(uint32_t i = 0; i < nsiblings; ++i)
1958 {
1959 if(i == idx)
1960 continue;
1961
1962 sibling_iterator ritr = sibling(litr, i);
1963
1964 if(!ritr)
1965 continue;
1966
1967 // skip if same iterator
1968 if(litr.node == ritr.node)
1969 continue;
1970
1971 if(_erase.find(ritr) != _erase.end())
1972 continue;
1973
1974 if(_compare(litr, ritr))
1975 {
1976 pre_order_iterator pritr(ritr);
1977 // printf("\n");
1978 // pre_order_iterator critr = pritr.begin();
1979 // auto aitr = append_child(litr, critr);
1980 auto aitr = insert_subgraph_after(litr, pritr);
1981 reduce(aitr.begin(), feet, _erase, _compare, _reduce);
1982 // insert_subgraph_after(litr, pritr);
1983 _erase.insert(ritr);
1984 reduce(litr.begin(), feet, _erase, _compare, _reduce);
1985 _reduce(litr, ritr);
1986 // this->erase(ritr);
1987
1988 // break;
1989 }
1990 }
1991
1992 for(auto& itr : _erase)
1993 this->erase(itr);
1994
1995 if(_erase.size() > 0)
1996 {
1997 _erase.clear();
1998 break;
1999 }
2000 // reduce(litr.begin(), feet, _erase, _compare, _reduce);
2001 }
2002}
void reduce(const sibling_iterator &, const sibling_iterator &, std::set< sibling_iterator > &, ComparePred &&=[](sibling_iterator lhs, sibling_iterator rhs) { return(*lhs== *rhs);}, ReducePred &&=[](sibling_iterator lhs, sibling_iterator rhs) { *lhs+= *rhs;})
Reduce duplicate nodes.
Definition: graph.hpp:1940
IterT insert_subgraph_after(IterT position, const iterator_base &subgraph)
Insert node (with children) pointed to by subgraph as next sibling of node pointed to by position.
Definition: graph.hpp:1252
sibling_iterator sibling(const iterator_base &position, unsigned int) const
Return iterator to the sibling indicated by index.
Definition: graph.hpp:2369
unsigned int index(sibling_iterator it) const
Determine the index of a node in the range of siblings to which it belongs.
Definition: graph.hpp:2339

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(), tim::graph< T, AllocatorT >::reduce(), and tim::graph< T, AllocatorT >::sibling().

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

◆ 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 1526 of file graph.hpp.

1527{
1528 if(from.node->first_child == nullptr)
1529 return position;
1530 return reparent(position, from.node->first_child, end(from));
1531}
IterT reparent(IterT position, sibling_iterator begin, const sibling_iterator &end)
Move nodes in range to be children of 'position'.
Definition: graph.hpp:1463

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 1463 of file graph.hpp.

1465{
1466 graph_node* first = _begin.node;
1467 graph_node* last = first;
1468
1469 assert(first != position.node);
1470
1471 if(_begin == _end)
1472 return _begin;
1473 // determine last node
1474 while((++_begin) != _end)
1475 {
1476 last = last->next_sibling;
1477 }
1478 // move subgraph
1479 if(first->prev_sibling == nullptr)
1480 {
1481 first->parent->first_child = last->next_sibling;
1482 }
1483 else
1484 {
1485 first->prev_sibling->next_sibling = last->next_sibling;
1486 }
1487 if(last->next_sibling == nullptr)
1488 {
1489 last->parent->last_child = first->prev_sibling;
1490 }
1491 else
1492 {
1493 last->next_sibling->prev_sibling = first->prev_sibling;
1494 }
1495 if(position.node->first_child == nullptr)
1496 {
1497 position.node->first_child = first;
1498 position.node->last_child = last;
1499 first->prev_sibling = nullptr;
1500 }
1501 else
1502 {
1503 position.node->last_child->next_sibling = first;
1504 first->prev_sibling = position.node->last_child;
1505 position.node->last_child = last;
1506 }
1507 last->next_sibling = nullptr;
1508
1509 graph_node* pos = first;
1510 for(;;)
1511 {
1512 pos->parent = position.node;
1513 if(pos == last)
1514 break;
1515 pos = pos->next_sibling;
1516 }
1517
1518 return first;
1519}

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 1303 of file graph.hpp.

1304{
1305 assert(position.node != head);
1306 graph_node* current_from = from.node;
1307 graph_node* start_from = from.node;
1308 graph_node* current_to = position.node;
1309
1310 // replace the node at position with head of the replacement graph at from
1311 // std::cout << "warning!" << position.node << std::endl;
1312 erase_children(position);
1313 // std::cout << "no warning!" << std::endl;
1314 graph_node* tmp = allocator_traits::allocate(*m_alloc, 1, nullptr);
1315 allocator_traits::construct(*m_alloc, tmp, (*from));
1316 tmp->first_child = nullptr;
1317 tmp->last_child = nullptr;
1318 if(current_to->prev_sibling == nullptr)
1319 {
1320 if(current_to->parent != nullptr)
1321 current_to->parent->first_child = tmp;
1322 }
1323 else
1324 {
1325 current_to->prev_sibling->next_sibling = tmp;
1326 }
1327 tmp->prev_sibling = current_to->prev_sibling;
1328 if(current_to->next_sibling == nullptr)
1329 {
1330 if(current_to->parent != nullptr)
1331 current_to->parent->last_child = tmp;
1332 }
1333 else
1334 {
1335 current_to->next_sibling->prev_sibling = tmp;
1336 }
1337 tmp->next_sibling = current_to->next_sibling;
1338 tmp->parent = current_to->parent;
1339 allocator_traits::destroy(*m_alloc, current_to);
1340 allocator_traits::deallocate(*m_alloc, current_to, 1);
1341 current_to = tmp;
1342
1343 // only at this stage can we fix 'last'
1344 graph_node* last = from.node->next_sibling;
1345
1346 pre_order_iterator toit = tmp;
1347 // copy all children
1348 do
1349 {
1350 assert(current_from != nullptr);
1351 if(current_from->first_child != nullptr)
1352 {
1353 current_from = current_from->first_child;
1354 toit = append_child(toit, current_from->data);
1355 }
1356 else
1357 {
1358 while(current_from->next_sibling == nullptr && current_from != start_from)
1359 {
1360 current_from = current_from->parent;
1361 toit = parent(toit);
1362 assert(current_from != nullptr);
1363 }
1364 current_from = current_from->next_sibling;
1365 if(current_from != last && current_from)
1366 {
1367 toit = append_child(parent(toit), current_from->data);
1368 }
1369 }
1370 } while(current_from != last && current_from);
1371
1372 return current_to;
1373}

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 1279 of file graph.hpp.

1280{
1281 allocator_traits::destroy(*m_alloc, position.node);
1282 allocator_traits::construct(*m_alloc, position.node, x);
1283 return position;
1284}

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 1291 of file graph.hpp.

1292{
1293 allocator_traits::destroy(*m_alloc, position.node);
1294 allocator_traits::construct(*m_alloc, position.node, std::forward<T>(x));
1295 return position;
1296}

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 1379 of file graph.hpp.

1382{
1383 graph_node* orig_first = orig_begin.node;
1384 graph_node* new_first = new_begin.node;
1385 graph_node* orig_last = orig_first;
1386 while((++orig_begin) != orig_end)
1387 orig_last = orig_last->next_sibling;
1388 graph_node* new_last = new_first;
1389 while((++new_begin) != new_end)
1390 new_last = new_last->next_sibling;
1391
1392 // insert all siblings in new_first..new_last before orig_first
1393 bool first = true;
1394 pre_order_iterator ret;
1395 while(true)
1396 {
1397 pre_order_iterator tt = insert_subgraph(pre_order_iterator(orig_first),
1398 pre_order_iterator(new_first));
1399 if(first)
1400 {
1401 ret = tt;
1402 first = false;
1403 }
1404 if(new_first == new_last)
1405 break;
1406 new_first = new_first->next_sibling;
1407 }
1408
1409 // erase old range of siblings
1410 bool last = false;
1411 graph_node* next = orig_first;
1412 while(true)
1413 {
1414 if(next == orig_last)
1415 last = true;
1416 next = next->next_sibling;
1417 erase((pre_order_iterator) orig_first);
1418 if(last)
1419 break;
1420 orig_first = next;
1421 }
1422 return ret;
1423}

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 530 of file graph.hpp.

531 {
532 for(auto itr = begin(); itr != end(); ++itr)
533 ar(cereal::make_nvp("node", *itr));
534 }

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 1057 of file graph.hpp.

1058{
1059 assert(head->next_sibling == feet);
1060 return insert(iterator(feet), x);
1061}
pre_order_iterator iterator
The default iterator types throughout the graph class.
Definition: graph.hpp:218

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

◆ 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 2369 of file graph.hpp.

2370{
2371 graph_node* tmp = it.node;
2372 if(!tmp)
2373 return sibling_iterator(nullptr);
2374
2375 if(tmp->parent != nullptr)
2376 {
2377 tmp = tmp->parent->first_child;
2378 }
2379 else
2380 {
2381 while(tmp->prev_sibling != nullptr)
2382 tmp = tmp->prev_sibling;
2383 }
2384
2385 while((num--) != 0u)
2386 {
2387 assert(tmp != nullptr);
2388 tmp = tmp->next_sibling;
2389 }
2390 return tmp;
2391}

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 2868 of file graph.hpp.

2869{
2870 size_t i = 0;
2871 pre_order_iterator bit = begin();
2872 pre_order_iterator eit = end();
2873 pre_order_iterator itr = bit;
2874 while(itr != eit)
2875 {
2876 ++i;
2877 ++itr;
2878 }
2879 return i;
2880}

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

◆ steal_resources()

template<typename T , typename AllocatorT >
void tim::graph< T, AllocatorT >::steal_resources ( this_type rhs)
inline

Definition at line 536 of file graph.hpp.

536{ m_stolen_alloc.emplace_back(rhs.m_alloc); }

◆ 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 2246 of file graph.hpp.

2247{
2248 // if one and two are adjacent siblings, use the sibling swap
2249 if(one.node->next_sibling == two.node)
2250 {
2251 swap(one);
2252 }
2253 else if(two.node->next_sibling == one.node)
2254 {
2255 swap(two);
2256 }
2257 else
2258 {
2259 graph_node* nxt1 = one.node->next_sibling;
2260 graph_node* nxt2 = two.node->next_sibling;
2261 graph_node* pre1 = one.node->prev_sibling;
2262 graph_node* pre2 = two.node->prev_sibling;
2263 graph_node* par1 = one.node->parent;
2264 graph_node* par2 = two.node->parent;
2265
2266 // reconnect
2267 one.node->parent = par2;
2268 one.node->next_sibling = nxt2;
2269 if(nxt2)
2270 {
2271 nxt2->prev_sibling = one.node;
2272 }
2273 else
2274 {
2275 par2->last_child = one.node;
2276 }
2277 one.node->prev_sibling = pre2;
2278 if(pre2)
2279 {
2280 pre2->next_sibling = one.node;
2281 }
2282 else
2283 {
2284 par2->first_child = one.node;
2285 }
2286
2287 two.node->parent = par1;
2288 two.node->next_sibling = nxt1;
2289 if(nxt1)
2290 {
2291 nxt1->prev_sibling = two.node;
2292 }
2293 else
2294 {
2295 par1->last_child = two.node;
2296 }
2297 two.node->prev_sibling = pre1;
2298 if(pre1)
2299 {
2300 pre1->next_sibling = two.node;
2301 }
2302 else
2303 {
2304 par1->first_child = two.node;
2305 }
2306 }
2307}
void swap(sibling_iterator it)
Exchange the node (plus subgraph) with its sibling node (do nothing if no sibling present).
Definition: graph.hpp:2213

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 2213 of file graph.hpp.

2214{
2215 graph_node* nxt = it.node->next_sibling;
2216 if(nxt)
2217 {
2218 if(it.node->prev_sibling)
2219 {
2220 it.node->prev_sibling->next_sibling = nxt;
2221 }
2222 else
2223 {
2224 it.node->parent->first_child = nxt;
2225 }
2226 nxt->prev_sibling = it.node->prev_sibling;
2227 graph_node* nxtnxt = nxt->next_sibling;
2228 if(nxtnxt)
2229 {
2230 nxtnxt->prev_sibling = it.node;
2231 }
2232 else
2233 {
2234 it.node->parent->last_child = it.node;
2235 }
2236 nxt->next_sibling = it.node;
2237 it.node->prev_sibling = nxt;
2238 it.node->next_sibling = nxtnxt;
2239 }
2240}

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 1554 of file graph.hpp.

1555{
1556 assert(from.node != nullptr);
1557 IterT ret = insert(from, x);
1558 reparent(ret, from, to);
1559 return ret;
1560}

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 1538 of file graph.hpp.

1539{
1540 assert(position.node != nullptr);
1541 sibling_iterator fr = position;
1542 sibling_iterator to = position;
1543 ++to;
1544 IterT ret = insert(position, x);
1545 reparent(ret, fr, to);
1546 return ret;
1547}

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: