| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- // Copyright (c) 2017 Google Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #ifndef SOURCE_OPT_TREE_ITERATOR_H_
- #define SOURCE_OPT_TREE_ITERATOR_H_
- #include <stack>
- #include <type_traits>
- #include <utility>
- namespace spvtools {
- namespace opt {
- // Helper class to iterate over a tree in a depth first order.
- // The class assumes the data structure is a tree, tree node type implements a
- // forward iterator.
- // At each step, the iterator holds the pointer to the current node and state of
- // the walk.
- // The state is recorded by stacking the iteration position of the node
- // children. To move to the next node, the iterator:
- // - Looks at the top of the stack;
- // - Sets the node behind the iterator as the current node;
- // - Increments the iterator if it has more children to visit, pops otherwise;
- // - If the current node has children, the children iterator is pushed into the
- // stack.
- template <typename NodeTy>
- class TreeDFIterator {
- static_assert(!std::is_pointer<NodeTy>::value &&
- !std::is_reference<NodeTy>::value,
- "NodeTy should be a class");
- // Type alias to keep track of the const qualifier.
- using NodeIterator =
- typename std::conditional<std::is_const<NodeTy>::value,
- typename NodeTy::const_iterator,
- typename NodeTy::iterator>::type;
- // Type alias to keep track of the const qualifier.
- using NodePtr = NodeTy*;
- public:
- // Standard iterator interface.
- using reference = NodeTy&;
- using value_type = NodeTy;
- explicit inline TreeDFIterator(NodePtr top_node) : current_(top_node) {
- if (current_ && current_->begin() != current_->end())
- parent_iterators_.emplace(make_pair(current_, current_->begin()));
- }
- // end() iterator.
- inline TreeDFIterator() : TreeDFIterator(nullptr) {}
- bool operator==(const TreeDFIterator& x) const {
- return current_ == x.current_;
- }
- bool operator!=(const TreeDFIterator& x) const { return !(*this == x); }
- reference operator*() const { return *current_; }
- NodePtr operator->() const { return current_; }
- TreeDFIterator& operator++() {
- MoveToNextNode();
- return *this;
- }
- TreeDFIterator operator++(int) {
- TreeDFIterator tmp = *this;
- ++*this;
- return tmp;
- }
- private:
- // Moves the iterator to the next node in the tree.
- // If we are at the end, do nothing, otherwise
- // if our current node has children, use the children iterator and push the
- // current node into the stack.
- // If we reach the end of the local iterator, pop it.
- inline void MoveToNextNode() {
- if (!current_) return;
- if (parent_iterators_.empty()) {
- current_ = nullptr;
- return;
- }
- std::pair<NodePtr, NodeIterator>& next_it = parent_iterators_.top();
- // Set the new node.
- current_ = *next_it.second;
- // Update the iterator for the next child.
- ++next_it.second;
- // If we finished with node, pop it.
- if (next_it.first->end() == next_it.second) parent_iterators_.pop();
- // If our current node is not a leaf, store the iteration state for later.
- if (current_->begin() != current_->end())
- parent_iterators_.emplace(make_pair(current_, current_->begin()));
- }
- // The current node of the tree.
- NodePtr current_;
- // State of the tree walk: each pair contains the parent node (which has been
- // already visited) and the iterator of the next children to visit.
- // When all the children has been visited, we pop the entry, get the next
- // child and push back the pair if the children iterator is not end().
- std::stack<std::pair<NodePtr, NodeIterator>> parent_iterators_;
- };
- // Helper class to iterate over a tree in a depth first post-order.
- // The class assumes the data structure is a tree, tree node type implements a
- // forward iterator.
- // At each step, the iterator holds the pointer to the current node and state of
- // the walk.
- // The state is recorded by stacking the iteration position of the node
- // children. To move to the next node, the iterator:
- // - Looks at the top of the stack;
- // - If the children iterator has reach the end, then the node become the
- // current one and we pop the stack;
- // - Otherwise, we save the child and increment the iterator;
- // - We walk the child sub-tree until we find a leaf, stacking all non-leaves
- // states (pair of node pointer and child iterator) as we walk it.
- template <typename NodeTy>
- class PostOrderTreeDFIterator {
- static_assert(!std::is_pointer<NodeTy>::value &&
- !std::is_reference<NodeTy>::value,
- "NodeTy should be a class");
- // Type alias to keep track of the const qualifier.
- using NodeIterator =
- typename std::conditional<std::is_const<NodeTy>::value,
- typename NodeTy::const_iterator,
- typename NodeTy::iterator>::type;
- // Type alias to keep track of the const qualifier.
- using NodePtr = NodeTy*;
- public:
- // Standard iterator interface.
- using reference = NodeTy&;
- using value_type = NodeTy;
- static inline PostOrderTreeDFIterator begin(NodePtr top_node) {
- return PostOrderTreeDFIterator(top_node);
- }
- static inline PostOrderTreeDFIterator end(NodePtr sentinel_node) {
- return PostOrderTreeDFIterator(sentinel_node, false);
- }
- bool operator==(const PostOrderTreeDFIterator& x) const {
- return current_ == x.current_;
- }
- bool operator!=(const PostOrderTreeDFIterator& x) const {
- return !(*this == x);
- }
- reference operator*() const { return *current_; }
- NodePtr operator->() const { return current_; }
- PostOrderTreeDFIterator& operator++() {
- MoveToNextNode();
- return *this;
- }
- PostOrderTreeDFIterator operator++(int) {
- PostOrderTreeDFIterator tmp = *this;
- ++*this;
- return tmp;
- }
- private:
- explicit inline PostOrderTreeDFIterator(NodePtr top_node)
- : current_(top_node) {
- if (current_) WalkToLeaf();
- }
- // Constructor for the "end()" iterator.
- // |end_sentinel| is the value that acts as end value (can be null). The bool
- // parameters is to distinguish from the start() Ctor.
- inline PostOrderTreeDFIterator(NodePtr sentinel_node, bool)
- : current_(sentinel_node) {}
- // Moves the iterator to the next node in the tree.
- // If we are at the end, do nothing, otherwise
- // if our current node has children, use the children iterator and push the
- // current node into the stack.
- // If we reach the end of the local iterator, pop it.
- inline void MoveToNextNode() {
- if (!current_) return;
- if (parent_iterators_.empty()) {
- current_ = nullptr;
- return;
- }
- std::pair<NodePtr, NodeIterator>& next_it = parent_iterators_.top();
- // If we visited all children, the current node is the top of the stack.
- if (next_it.second == next_it.first->end()) {
- // Set the new node.
- current_ = next_it.first;
- parent_iterators_.pop();
- return;
- }
- // We have more children to visit, set the current node to the first child
- // and dive to leaf.
- current_ = *next_it.second;
- // Update the iterator for the next child (avoid unneeded pop).
- ++next_it.second;
- WalkToLeaf();
- }
- // Moves the iterator to the next node in the tree.
- // If we are at the end, do nothing, otherwise
- // if our current node has children, use the children iterator and push the
- // current node into the stack.
- // If we reach the end of the local iterator, pop it.
- inline void WalkToLeaf() {
- while (current_->begin() != current_->end()) {
- NodeIterator next = ++current_->begin();
- parent_iterators_.emplace(make_pair(current_, next));
- // Set the first child as the new node.
- current_ = *current_->begin();
- }
- }
- // The current node of the tree.
- NodePtr current_;
- // State of the tree walk: each pair contains the parent node and the iterator
- // of the next children to visit.
- // When all the children has been visited, we pop the first entry and the
- // parent node become the current node.
- std::stack<std::pair<NodePtr, NodeIterator>> parent_iterators_;
- };
- } // namespace opt
- } // namespace spvtools
- #endif // SOURCE_OPT_TREE_ITERATOR_H_
|