A library for working with phylogenetic and population genetic data.
v0.32.0
tree/iterator/postorder.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_TREE_ITERATOR_POSTORDER_H_
2 #define GENESIS_TREE_ITERATOR_POSTORDER_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2024 Lucas Czech
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lucas.czech@sund.ku.dk>
23  University of Copenhagen, Globe Institute, Section for GeoGenetics
24  Oster Voldgade 5-7, 1350 Copenhagen K, Denmark
25 */
26 
34 #include "genesis/tree/tree.hpp"
37 
38 #include <algorithm>
39 #include <cassert>
40 #include <iterator>
41 #include <type_traits>
42 #include <vector>
43 
44 namespace genesis {
45 namespace tree {
46 
47 // =================================================================================================
48 // Forward Declarations
49 // =================================================================================================
50 
51 class Tree;
52 class TreeNode;
53 class TreeEdge;
54 class TreeLink;
55 class Subtree;
56 
57 // =================================================================================================
58 // Postorder Iterator
59 // =================================================================================================
60 
61 template< bool is_const = true >
63 {
64 
65 public:
66 
67  // -----------------------------------------------------
68  // Typedefs
69  // -----------------------------------------------------
70 
71  // Make the memer types const or not, depending on iterator type.
72  using TreeType = typename std::conditional< is_const, Tree const, Tree >::type;
73  using LinkType = typename std::conditional< is_const, TreeLink const, TreeLink >::type;
74  using NodeType = typename std::conditional< is_const, TreeNode const, TreeNode >::type;
75  using EdgeType = typename std::conditional< is_const, TreeEdge const, TreeEdge >::type;
76 
78  using iterator_category = std::forward_iterator_tag;
79  // using value_type = NodeType;
80  // using pointer = NodeType*;
81  // using reference = NodeType&;
82  // using difference_type = std::ptrdiff_t;
83 
84  // -----------------------------------------------------
85  // Constructors and Rule of Five
86  // -----------------------------------------------------
87 
89  : start_( nullptr )
90  , link_ ( nullptr )
91  {}
92 
96  explicit IteratorPostorder( TreeType& tree )
97  : IteratorPostorder( tree.root_link() )
98  {}
99 
109  : IteratorPostorder( node.primary_link() )
110  {}
111 
122  : start_( &link )
123  {
124  // The stack keeps links to nodes that yet need to be visited.
125  // These are the links that point towards the start link.
126 
127  // Fill in the start link. This will be the last node visited.
128  auto link_ptr = &link;
129  stack_.push_back( link_ptr );
130 
131  // Now start traversing in the direction of this link.
132  stack_.push_back( &link_ptr->outer() );
133  link_ptr = &link_ptr->outer();
134 
135  // Add all inner nodes along the first path, until we reach a leaf.
136  while( is_inner_( *link_ptr )) {
137  push_back_children_( link_ptr );
138  link_ptr = &link_ptr->next().outer();
139  }
140 
141  // The fist leaf that we found is the last link that was added.
142  // Remove it from the stack again, because this is where we stop - this is the first
143  // node being visited, and hence does not need to be on the stack any more
144  // (it was added to keep the push_back_children fct simple and without edge case).
145  assert( link_ptr == stack_.back() );
146  stack_.pop_back();
147  link_ = link_ptr;
148  }
149 
154  explicit IteratorPostorder( Subtree const& subtree )
155  : start_( &(subtree.link()) )
156  {
157  // Add the starting/subtree link as the final one to the stack.
158  auto link_ptr = &(subtree.link());
159  stack_.push_back( link_ptr );
160 
161  // Compared to the normal constructor above, we simply leave out the part
162  // where we move in the outer() direction of the link, and instead just continue
163  // in the direction of the subtree itself.
164 
165  // Find the first leaf.
166  while( is_inner_( *link_ptr )) {
167  push_back_children_( link_ptr );
168  link_ptr = &link_ptr->next().outer();
169  }
170 
171  // The leaf that was last added is the one that we visit now.
172  // Remove it again, as we are here now.
173  assert( link_ptr == stack_.back() );
174  stack_.pop_back();
175  link_ = link_ptr;
176  }
177 
178  ~IteratorPostorder() = default;
179 
180  IteratorPostorder( IteratorPostorder const& ) = default;
181  IteratorPostorder( IteratorPostorder&& ) = default;
182 
183  IteratorPostorder& operator= ( IteratorPostorder const& ) = default;
185 
186  // -----------------------------------------------------
187  // Operators
188  // -----------------------------------------------------
189 
191  {
192  return *this;
193  }
194 
196  {
197  if( stack_.empty() ) {
198 
199  // This condition marks the end of the traversal:
200  // There are no more links on the stack to be visited.
201  link_ = nullptr;
202 
203  } else if( &link_->outer().next() == stack_.back() ) {
204 
205  // This condition is active when seeing an inner node the last time,
206  // meaning that it is its turn to be visited.
207  link_ = stack_.back();
208  stack_.pop_back();
209 
210  } else {
211 
212  // This condition is active in all other cases: going down the tree towards the leaves.
213  // That means, we are in a part that is not yet on the stack, so we need to add it.
214  link_ = stack_.back();
215  while( is_inner_( *link_ )) {
216  push_back_children_(link_);
217  link_ = &link_->next().outer();
218  }
219  assert( link_ == stack_.back() );
220  stack_.pop_back();
221  }
222 
223  return *this;
224  }
225 
227  {
228  self_type tmp = *this;
229  ++(*this);
230  return tmp;
231  }
232 
233  bool operator == (const self_type &other) const
234  {
235  return other.link_ == link_;
236  }
237 
238  bool operator != (const self_type &other) const
239  {
240  return !(other == *this);
241  }
242 
243  // -----------------------------------------------------
244  // Members
245  // -----------------------------------------------------
246 
247  bool is_last_iteration() const
248  {
249  return link_ == start_;
250  }
251 
252  LinkType& link() const
253  {
254  return *link_;
255  }
256 
257  NodeType& node() const
258  {
259  return link_->node();
260  }
261 
262  EdgeType& edge() const
263  {
264  return link_->edge();
265  }
266 
268  {
269  return *start_;
270  }
271 
273  {
274  return start_->node();
275  }
276 
277 private:
278 
279  // -----------------------------------------------------
280  // Internal Helper Functions
281  // -----------------------------------------------------
282 
283  void push_back_children_( LinkType* link )
284  {
285  // We add the children, and at the end reverse their order.
286  // Otherwise, we would still do a postorder traversal, but starting with
287  // the last child of each node instead of the first one.
288  size_t push_cnt = 0;
289  LinkType* c = &link->next();
290  while( c != link ) {
291  stack_.push_back( &c->outer() );
292  ++push_cnt;
293  c = &c->next();
294  }
295  assert( stack_.size() >= push_cnt );
296  std::reverse( stack_.end() - push_cnt, stack_.end() );
297  }
298 
299  bool is_inner_( TreeLink const& link )
300  {
301  // Duplication of the free function. But this avoids pulling in the header.
302  return &( link.next() ) != &link;
303  }
304 
305  // -----------------------------------------------------
306  // Data Members
307  // -----------------------------------------------------
308 
309  LinkType* const start_;
310  LinkType* link_;
311 
312  std::vector<LinkType*> stack_;
313 };
314 
315 // =================================================================================================
316 // Postorder Wrapper Functions
317 // =================================================================================================
318 
319 template<typename ElementType>
320 utils::Range< IteratorPostorder< true >>
321 postorder( ElementType const& element )
322 {
323  return {
324  IteratorPostorder< true >( element ),
326  };
327 }
328 
329 template<typename ElementType>
331 postorder( ElementType& element )
332 {
333  return {
334  IteratorPostorder< false >( element ),
336  };
337 }
338 
339 } // namespace tree
340 } // namespace genesis
341 
342 #endif // include guard
genesis::tree::Subtree::link
TreeLink const & link() const
Get the TreeLink that separates the subtree from the rest of the tree.
Definition: subtree.hpp:125
genesis::tree::IteratorPostorder::LinkType
typename std::conditional< is_const, TreeLink const, TreeLink >::type LinkType
Definition: tree/iterator/postorder.hpp:73
genesis::tree::IteratorPostorder::edge
EdgeType & edge() const
Definition: tree/iterator/postorder.hpp:262
genesis::tree::IteratorPostorder::~IteratorPostorder
~IteratorPostorder()=default
tree.hpp
Header of Tree class.
genesis::tree::IteratorPostorder::node
NodeType & node() const
Definition: tree/iterator/postorder.hpp:257
genesis::tree::IteratorPostorder::IteratorPostorder
IteratorPostorder(NodeType &node)
Start a postorder traversal at the given TreeNode, moving in the root direction first.
Definition: tree/iterator/postorder.hpp:108
genesis::tree::IteratorPostorder::IteratorPostorder
IteratorPostorder()
Definition: tree/iterator/postorder.hpp:88
subtree.hpp
genesis::tree::IteratorPostorder::NodeType
typename std::conditional< is_const, TreeNode const, TreeNode >::type NodeType
Definition: tree/iterator/postorder.hpp:74
genesis::tree::IteratorPostorder::operator==
bool operator==(const self_type &other) const
Definition: tree/iterator/postorder.hpp:233
range.hpp
genesis::tree::Subtree
Reference to a subtree of a Tree.
Definition: subtree.hpp:69
genesis::tree::IteratorPostorder
Definition: tree/iterator/postorder.hpp:62
genesis::tree::IteratorPostorder::IteratorPostorder
IteratorPostorder(LinkType &link)
Start a postorder traversal at a given TreeLink, moving in the direction of the link first.
Definition: tree/iterator/postorder.hpp:121
genesis::tree::IteratorPostorder::operator*
self_type operator*()
Definition: tree/iterator/postorder.hpp:190
genesis::utils::Range
Simple wrapper for typical begin() and end() iterators, to be used in range-based for loops.
Definition: range.hpp:46
genesis::tree::IteratorPostorder::start_link
LinkType & start_link() const
Definition: tree/iterator/postorder.hpp:267
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::tree::IteratorPostorder::is_last_iteration
bool is_last_iteration() const
Definition: tree/iterator/postorder.hpp:247
genesis::tree::IteratorPostorder::operator=
IteratorPostorder & operator=(IteratorPostorder const &)=default
genesis::tree::IteratorPostorder::operator!=
bool operator!=(const self_type &other) const
Definition: tree/iterator/postorder.hpp:238
genesis::tree::IteratorPostorder::IteratorPostorder
IteratorPostorder(TreeType &tree)
Start a postorder traversal at the root of the given Tree.
Definition: tree/iterator/postorder.hpp:96
genesis::tree::IteratorPostorder::TreeType
typename std::conditional< is_const, Tree const, Tree >::type TreeType
Definition: tree/iterator/postorder.hpp:72
genesis::tree::IteratorPostorder::EdgeType
typename std::conditional< is_const, TreeEdge const, TreeEdge >::type EdgeType
Definition: tree/iterator/postorder.hpp:75
genesis::tree::IteratorPostorder::IteratorPostorder
IteratorPostorder(Subtree const &subtree)
Start a postorder traversal at the top TreeNode of a Subtree, only traversing the nodes in the subtre...
Definition: tree/iterator/postorder.hpp:154
genesis::tree::IteratorPostorder::iterator_category
std::forward_iterator_tag iterator_category
Definition: tree/iterator/postorder.hpp:78
genesis::tree::IteratorPostorder::start_node
NodeType & start_node() const
Definition: tree/iterator/postorder.hpp:272
genesis::tree::postorder
utils::Range< IteratorPostorder< true > > postorder(ElementType const &element)
Definition: tree/iterator/postorder.hpp:321
genesis::tree::IteratorPostorder::operator++
self_type operator++()
Definition: tree/iterator/postorder.hpp:195
genesis::tree::IteratorPostorder::link
LinkType & link() const
Definition: tree/iterator/postorder.hpp:252