xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ADT/DepthFirstIterator.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1 //===- llvm/ADT/DepthFirstIterator.h - Depth First iterator -----*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file builds on the ADT/GraphTraits.h file to build generic depth
11 /// first graph iterator.  This file exposes the following functions/types:
12 ///
13 /// df_begin/df_end/df_iterator
14 ///   * Normal depth-first iteration - visit a node and then all of its
15 ///     children.
16 ///
17 /// idf_begin/idf_end/idf_iterator
18 ///   * Depth-first iteration on the 'inverse' graph.
19 ///
20 /// df_ext_begin/df_ext_end/df_ext_iterator
21 ///   * Normal depth-first iteration - visit a node and then all of its
22 ///     children. This iterator stores the 'visited' set in an external set,
23 ///     which allows it to be more efficient, and allows external clients to
24 ///     use the set for other purposes.
25 ///
26 /// idf_ext_begin/idf_ext_end/idf_ext_iterator
27 ///   * Depth-first iteration on the 'inverse' graph.
28 ///     This iterator stores the 'visited' set in an external set, which
29 ///     allows it to be more efficient, and allows external clients to use
30 ///     the set for other purposes.
31 ///
32 //===----------------------------------------------------------------------===//
33 
34 #ifndef LLVM_ADT_DEPTHFIRSTITERATOR_H
35 #define LLVM_ADT_DEPTHFIRSTITERATOR_H
36 
37 #include "llvm/ADT/GraphTraits.h"
38 #include "llvm/ADT/SmallPtrSet.h"
39 #include "llvm/ADT/iterator_range.h"
40 #include <iterator>
41 #include <optional>
42 #include <utility>
43 #include <vector>
44 
45 namespace llvm {
46 
47 // df_iterator_storage - A private class which is used to figure out where to
48 // store the visited set.
49 template<class SetType, bool External>   // Non-external set
50 class df_iterator_storage {
51 public:
52   SetType Visited;
53 };
54 
55 template<class SetType>
56 class df_iterator_storage<SetType, true> {
57 public:
df_iterator_storage(SetType & VSet)58   df_iterator_storage(SetType &VSet) : Visited(VSet) {}
df_iterator_storage(const df_iterator_storage & S)59   df_iterator_storage(const df_iterator_storage &S) : Visited(S.Visited) {}
60 
61   SetType &Visited;
62 };
63 
64 // The visited stated for the iteration is a simple set augmented with
65 // one more method, completed, which is invoked when all children of a
66 // node have been processed. It is intended to distinguish of back and
67 // cross edges in the spanning tree but is not used in the common case.
68 template <typename NodeRef, unsigned SmallSize=8>
69 struct df_iterator_default_set : public SmallPtrSet<NodeRef, SmallSize> {
70   using BaseSet = SmallPtrSet<NodeRef, SmallSize>;
71   using iterator = typename BaseSet::iterator;
72 
insertdf_iterator_default_set73   std::pair<iterator,bool> insert(NodeRef N) { return BaseSet::insert(N); }
74   template <typename IterT>
insertdf_iterator_default_set75   void insert(IterT Begin, IterT End) { BaseSet::insert(Begin,End); }
76 
completeddf_iterator_default_set77   void completed(NodeRef) {}
78 };
79 
80 // Generic Depth First Iterator
81 template <class GraphT,
82           class SetType =
83               df_iterator_default_set<typename GraphTraits<GraphT>::NodeRef>,
84           bool ExtStorage = false, class GT = GraphTraits<GraphT>>
85 class df_iterator : public df_iterator_storage<SetType, ExtStorage> {
86 public:
87   using iterator_category = std::forward_iterator_tag;
88   using value_type = typename GT::NodeRef;
89   using difference_type = std::ptrdiff_t;
90   using pointer = value_type *;
91   using reference = const value_type &;
92 
93 private:
94   using NodeRef = typename GT::NodeRef;
95   using ChildItTy = typename GT::ChildIteratorType;
96 
97   // First element is node reference, second is the 'next child' to visit.
98   // The second child is initialized lazily to pick up graph changes during the
99   // DFS.
100   using StackElement = std::pair<NodeRef, std::optional<ChildItTy>>;
101 
102   // VisitStack - Used to maintain the ordering.  Top = current block
103   std::vector<StackElement> VisitStack;
104 
df_iterator(NodeRef Node)105   inline df_iterator(NodeRef Node) {
106     this->Visited.insert(Node);
107     VisitStack.push_back(StackElement(Node, std::nullopt));
108   }
109 
110   inline df_iterator() = default; // End is when stack is empty
111 
df_iterator(NodeRef Node,SetType & S)112   inline df_iterator(NodeRef Node, SetType &S)
113       : df_iterator_storage<SetType, ExtStorage>(S) {
114     if (this->Visited.insert(Node).second)
115       VisitStack.push_back(StackElement(Node, std::nullopt));
116   }
117 
df_iterator(SetType & S)118   inline df_iterator(SetType &S)
119     : df_iterator_storage<SetType, ExtStorage>(S) {
120     // End is when stack is empty
121   }
122 
toNext()123   inline void toNext() {
124     do {
125       NodeRef Node = VisitStack.back().first;
126       std::optional<ChildItTy> &Opt = VisitStack.back().second;
127 
128       if (!Opt)
129         Opt.emplace(GT::child_begin(Node));
130 
131       // Notice that we directly mutate *Opt here, so that
132       // VisitStack.back().second actually gets updated as the iterator
133       // increases.
134       while (*Opt != GT::child_end(Node)) {
135         NodeRef Next = *(*Opt)++;
136         // Has our next sibling been visited?
137         if (this->Visited.insert(Next).second) {
138           // No, do it now.
139           VisitStack.push_back(StackElement(Next, std::nullopt));
140           return;
141         }
142       }
143       this->Visited.completed(Node);
144 
145       // Oops, ran out of successors... go up a level on the stack.
146       VisitStack.pop_back();
147     } while (!VisitStack.empty());
148   }
149 
150 public:
151   // Provide static begin and end methods as our public "constructors"
begin(const GraphT & G)152   static df_iterator begin(const GraphT &G) {
153     return df_iterator(GT::getEntryNode(G));
154   }
end(const GraphT & G)155   static df_iterator end(const GraphT &G) { return df_iterator(); }
156 
157   // Static begin and end methods as our public ctors for external iterators
begin(const GraphT & G,SetType & S)158   static df_iterator begin(const GraphT &G, SetType &S) {
159     return df_iterator(GT::getEntryNode(G), S);
160   }
end(const GraphT & G,SetType & S)161   static df_iterator end(const GraphT &G, SetType &S) { return df_iterator(S); }
162 
163   bool operator==(const df_iterator &x) const {
164     return VisitStack == x.VisitStack;
165   }
166   bool operator!=(const df_iterator &x) const { return !(*this == x); }
167 
168   reference operator*() const { return VisitStack.back().first; }
169 
170   // This is a nonstandard operator-> that dereferences the pointer an extra
171   // time... so that you can actually call methods ON the Node, because
172   // the contained type is a pointer.  This allows BBIt->getTerminator() f.e.
173   //
174   NodeRef operator->() const { return **this; }
175 
176   df_iterator &operator++() { // Preincrement
177     toNext();
178     return *this;
179   }
180 
181   /// Skips all children of the current node and traverses to next node
182   ///
183   /// Note: This function takes care of incrementing the iterator. If you
184   /// always increment and call this function, you risk walking off the end.
skipChildren()185   df_iterator &skipChildren() {
186     VisitStack.pop_back();
187     if (!VisitStack.empty())
188       toNext();
189     return *this;
190   }
191 
192   df_iterator operator++(int) { // Postincrement
193     df_iterator tmp = *this;
194     ++*this;
195     return tmp;
196   }
197 
198   // nodeVisited - return true if this iterator has already visited the
199   // specified node.  This is public, and will probably be used to iterate over
200   // nodes that a depth first iteration did not find: ie unreachable nodes.
201   //
nodeVisited(NodeRef Node)202   bool nodeVisited(NodeRef Node) const {
203     return this->Visited.contains(Node);
204   }
205 
206   /// getPathLength - Return the length of the path from the entry node to the
207   /// current node, counting both nodes.
getPathLength()208   unsigned getPathLength() const { return VisitStack.size(); }
209 
210   /// getPath - Return the n'th node in the path from the entry node to the
211   /// current node.
getPath(unsigned n)212   NodeRef getPath(unsigned n) const { return VisitStack[n].first; }
213 };
214 
215 // Provide global constructors that automatically figure out correct types...
216 //
217 template <class T>
df_begin(const T & G)218 df_iterator<T> df_begin(const T& G) {
219   return df_iterator<T>::begin(G);
220 }
221 
222 template <class T>
df_end(const T & G)223 df_iterator<T> df_end(const T& G) {
224   return df_iterator<T>::end(G);
225 }
226 
227 // Provide an accessor method to use them in range-based patterns.
228 template <class T>
depth_first(const T & G)229 iterator_range<df_iterator<T>> depth_first(const T& G) {
230   return make_range(df_begin(G), df_end(G));
231 }
232 
233 // Provide global definitions of external depth first iterators...
234 template <class T, class SetTy = df_iterator_default_set<typename GraphTraits<T>::NodeRef>>
235 struct df_ext_iterator : public df_iterator<T, SetTy, true> {
df_ext_iteratordf_ext_iterator236   df_ext_iterator(const df_iterator<T, SetTy, true> &V)
237     : df_iterator<T, SetTy, true>(V) {}
238 };
239 
240 template <class T, class SetTy>
df_ext_begin(const T & G,SetTy & S)241 df_ext_iterator<T, SetTy> df_ext_begin(const T& G, SetTy &S) {
242   return df_ext_iterator<T, SetTy>::begin(G, S);
243 }
244 
245 template <class T, class SetTy>
df_ext_end(const T & G,SetTy & S)246 df_ext_iterator<T, SetTy> df_ext_end(const T& G, SetTy &S) {
247   return df_ext_iterator<T, SetTy>::end(G, S);
248 }
249 
250 template <class T, class SetTy>
depth_first_ext(const T & G,SetTy & S)251 iterator_range<df_ext_iterator<T, SetTy>> depth_first_ext(const T& G,
252                                                           SetTy &S) {
253   return make_range(df_ext_begin(G, S), df_ext_end(G, S));
254 }
255 
256 // Provide global definitions of inverse depth first iterators...
257 template <class T,
258           class SetTy =
259               df_iterator_default_set<typename GraphTraits<T>::NodeRef>,
260           bool External = false>
261 struct idf_iterator : public df_iterator<Inverse<T>, SetTy, External> {
idf_iteratoridf_iterator262   idf_iterator(const df_iterator<Inverse<T>, SetTy, External> &V)
263     : df_iterator<Inverse<T>, SetTy, External>(V) {}
264 };
265 
266 template <class T>
idf_begin(const T & G)267 idf_iterator<T> idf_begin(const T& G) {
268   return idf_iterator<T>::begin(Inverse<T>(G));
269 }
270 
271 template <class T>
idf_end(const T & G)272 idf_iterator<T> idf_end(const T& G){
273   return idf_iterator<T>::end(Inverse<T>(G));
274 }
275 
276 // Provide an accessor method to use them in range-based patterns.
277 template <class T>
inverse_depth_first(const T & G)278 iterator_range<idf_iterator<T>> inverse_depth_first(const T& G) {
279   return make_range(idf_begin(G), idf_end(G));
280 }
281 
282 // Provide global definitions of external inverse depth first iterators...
283 template <class T, class SetTy = df_iterator_default_set<typename GraphTraits<T>::NodeRef>>
284 struct idf_ext_iterator : public idf_iterator<T, SetTy, true> {
idf_ext_iteratoridf_ext_iterator285   idf_ext_iterator(const idf_iterator<T, SetTy, true> &V)
286     : idf_iterator<T, SetTy, true>(V) {}
idf_ext_iteratoridf_ext_iterator287   idf_ext_iterator(const df_iterator<Inverse<T>, SetTy, true> &V)
288     : idf_iterator<T, SetTy, true>(V) {}
289 };
290 
291 template <class T, class SetTy>
idf_ext_begin(const T & G,SetTy & S)292 idf_ext_iterator<T, SetTy> idf_ext_begin(const T& G, SetTy &S) {
293   return idf_ext_iterator<T, SetTy>::begin(Inverse<T>(G), S);
294 }
295 
296 template <class T, class SetTy>
idf_ext_end(const T & G,SetTy & S)297 idf_ext_iterator<T, SetTy> idf_ext_end(const T& G, SetTy &S) {
298   return idf_ext_iterator<T, SetTy>::end(Inverse<T>(G), S);
299 }
300 
301 template <class T, class SetTy>
inverse_depth_first_ext(const T & G,SetTy & S)302 iterator_range<idf_ext_iterator<T, SetTy>> inverse_depth_first_ext(const T& G,
303                                                                    SetTy &S) {
304   return make_range(idf_ext_begin(G, S), idf_ext_end(G, S));
305 }
306 
307 } // end namespace llvm
308 
309 #endif // LLVM_ADT_DEPTHFIRSTITERATOR_H
310