LLVM 23.0.0git
DepthFirstIterator.h
Go to the documentation of this file.
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
40#include <iterator>
41#include <optional>
42#include <type_traits>
43#include <utility>
44#include <vector>
45
46namespace llvm {
47
48// df_iterator_storage - A private class which is used to figure out where to
49// store the visited set.
50template<class SetType, bool External> // Non-external set
52public:
53 SetType Visited;
54};
55
56template<class SetType>
57class df_iterator_storage<SetType, true> {
58public:
59 df_iterator_storage(SetType &VSet) : Visited(VSet) {}
61
62 SetType &Visited;
63};
64
65// The visited stated for the iteration is a simple set augmented with
66// one more method, completed, which is invoked when all children of a
67// node have been processed. It is intended to distinguish of back and
68// cross edges in the spanning tree but is not used in the common case.
69template <typename NodeRef, unsigned SmallSize = 8>
70struct df_iterator_default_set : SmallPtrSet<NodeRef, SmallSize> {
72 using iterator = typename BaseSet::iterator;
73
74 std::pair<iterator,bool> insert(NodeRef N) { return BaseSet::insert(N); }
75 template <typename IterT>
76 void insert(IterT Begin, IterT End) { BaseSet::insert(Begin,End); }
77
78 void completed(NodeRef) {}
79};
80
81// Generic Depth First Iterator
82template <class GraphT,
83 class SetType =
84 df_iterator_default_set<typename GraphTraits<GraphT>::NodeRef>,
85 bool ExtStorage = false, class GT = GraphTraits<GraphT>>
86class df_iterator : public df_iterator_storage<SetType, ExtStorage> {
87public:
88 // When External storage is used we are not multi-pass safe.
90 std::conditional_t<ExtStorage, std::input_iterator_tag,
91 std::forward_iterator_tag>;
92 using value_type = typename GT::NodeRef;
93 using difference_type = std::ptrdiff_t;
95 using reference = const value_type &;
96
97private:
98 using NodeRef = typename GT::NodeRef;
99 using ChildItTy = typename GT::ChildIteratorType;
100
101 // First element is node reference, second is the 'next child' to visit.
102 // The second child is initialized lazily to pick up graph changes during the
103 // DFS.
104 using StackElement = std::pair<NodeRef, std::optional<ChildItTy>>;
105
106 // VisitStack - Used to maintain the ordering. Top = current block
107 std::vector<StackElement> VisitStack;
108
109 inline df_iterator(NodeRef Node) {
110 this->Visited.insert(Node);
111 VisitStack.push_back(StackElement(Node, std::nullopt));
112 }
113
114 inline df_iterator() = default; // End is when stack is empty
115
116 inline df_iterator(NodeRef Node, SetType &S)
117 : df_iterator_storage<SetType, ExtStorage>(S) {
118 if (this->Visited.insert(Node).second)
119 VisitStack.push_back(StackElement(Node, std::nullopt));
120 }
121
122 inline df_iterator(SetType &S)
123 : df_iterator_storage<SetType, ExtStorage>(S) {
124 // End is when stack is empty
125 }
126
127 inline void toNext() {
128 do {
129 NodeRef Node = VisitStack.back().first;
130 std::optional<ChildItTy> &Opt = VisitStack.back().second;
131
132 if (!Opt)
133 Opt.emplace(GT::child_begin(Node));
134
135 // Notice that we directly mutate *Opt here, so that
136 // VisitStack.back().second actually gets updated as the iterator
137 // increases.
138 while (*Opt != GT::child_end(Node)) {
139 NodeRef Next = *(*Opt)++;
140 // Has our next sibling been visited?
141 if (this->Visited.insert(Next).second) {
142 // No, do it now.
143 VisitStack.push_back(StackElement(Next, std::nullopt));
144 return;
145 }
146 }
147 this->Visited.completed(Node);
148
149 // Oops, ran out of successors... go up a level on the stack.
150 VisitStack.pop_back();
151 } while (!VisitStack.empty());
152 }
153
154public:
155 // Provide static begin and end methods as our public "constructors"
156 static df_iterator begin(const GraphT &G) {
157 return df_iterator(GT::getEntryNode(G));
158 }
159 static df_iterator end(const GraphT &G) { return df_iterator(); }
160
161 // Static begin and end methods as our public ctors for external iterators
162 static df_iterator begin(const GraphT &G, SetType &S) {
163 return df_iterator(GT::getEntryNode(G), S);
164 }
165 static df_iterator end(const GraphT &G, SetType &S) { return df_iterator(S); }
166
167 bool operator==(const df_iterator &x) const {
168 return VisitStack == x.VisitStack;
169 }
170 bool operator!=(const df_iterator &x) const { return !(*this == x); }
171
172 reference operator*() const { return VisitStack.back().first; }
173
174 // This is a nonstandard operator-> that dereferences the pointer an extra
175 // time... so that you can actually call methods ON the Node, because
176 // the contained type is a pointer. This allows BBIt->getTerminator() f.e.
177 //
178 NodeRef operator->() const { return **this; }
179
180 df_iterator &operator++() { // Preincrement
181 toNext();
182 return *this;
183 }
184
185 /// Skips all children of the current node and traverses to next node
186 ///
187 /// Note: This function takes care of incrementing the iterator. If you
188 /// always increment and call this function, you risk walking off the end.
189 df_iterator &skipChildren() {
190 VisitStack.pop_back();
191 if (!VisitStack.empty())
192 toNext();
193 return *this;
194 }
195
196 df_iterator operator++(int) { // Postincrement
197 df_iterator tmp = *this;
198 ++*this;
199 return tmp;
200 }
201
202 // nodeVisited - return true if this iterator has already visited the
203 // specified node. This is public, and will probably be used to iterate over
204 // nodes that a depth first iteration did not find: ie unreachable nodes.
205 //
206 bool nodeVisited(NodeRef Node) const {
207 return this->Visited.contains(Node);
208 }
209
210 /// Return the length of the path from the entry node to the current node,
211 /// counting both nodes.
212 unsigned getPathLength() const { return VisitStack.size(); }
213
214 /// Return the n'th node in the path from the entry node to the current node.
215 NodeRef getPath(unsigned n) const { return VisitStack[n].first; }
216};
217
218// Provide global constructors that automatically figure out correct types...
219//
220template <class T>
222 return df_iterator<T>::begin(G);
223}
224
225template <class T>
227 return df_iterator<T>::end(G);
228}
229
230// Provide an accessor method to use them in range-based patterns.
231template <class T>
235
236// Provide global definitions of external depth first iterators...
237template <class T,
238 class SetTy =
239 df_iterator_default_set<typename GraphTraits<T>::NodeRef>>
240struct df_ext_iterator : df_iterator<T, SetTy, true> {
241 df_ext_iterator(const df_iterator<T, SetTy, true> &V)
242 : df_iterator<T, SetTy, true>(V) {}
243};
244
245template <class T, class SetTy>
249
250template <class T, class SetTy>
254
255template <class T, class SetTy>
260
261// Provide global definitions of inverse depth first iterators...
262template <class T,
263 class SetTy =
264 df_iterator_default_set<typename GraphTraits<T>::NodeRef>,
265 bool External = false>
266struct idf_iterator : df_iterator<Inverse<T>, SetTy, External> {
267 idf_iterator(const df_iterator<Inverse<T>, SetTy, External> &V)
268 : df_iterator<Inverse<T>, SetTy, External>(V) {}
269};
270
271template <class T>
275
276template <class T>
280
281// Provide an accessor method to use them in range-based patterns.
282template <class T>
286
287// Provide global definitions of external inverse depth first iterators...
288template <class T,
289 class SetTy =
290 df_iterator_default_set<typename GraphTraits<T>::NodeRef>>
291struct idf_ext_iterator : idf_iterator<T, SetTy, true> {
295 : idf_iterator<T, SetTy, true>(V) {}
296};
297
298template <class T, class SetTy>
302
303template <class T, class SetTy>
307
308template <class T, class SetTy>
313
314} // end namespace llvm
315
316#endif // LLVM_ADT_DEPTHFIRSTITERATOR_H
This file defines the little GraphTraits<X> template class that should be specialized by classes that...
#define G(x, y, z)
Definition MD5.cpp:55
#define T
This file defines the SmallPtrSet class.
std::pair< iterator, bool > insert(NodeRef Ptr)
SmallPtrSetIterator< NodeRef > iterator
df_iterator_storage(const df_iterator_storage &S)
df_iterator & operator++()
static df_iterator begin(const GraphT &G)
NodeRef operator->() const
std::conditional_t< ExtStorage, std::input_iterator_tag, std::forward_iterator_tag > iterator_category
static df_iterator end(const GraphT &G)
const value_type & reference
static df_iterator end(const GraphT &G, SetType &S)
df_iterator & skipChildren()
Skips all children of the current node and traverses to next node.
unsigned getPathLength() const
Return the length of the path from the entry node to the current node, counting both nodes.
bool operator==(const df_iterator &x) const
df_iterator operator++(int)
bool operator!=(const df_iterator &x) const
bool nodeVisited(NodeRef Node) const
NodeRef getPath(unsigned n) const
Return the n'th node in the path from the entry node to the current node.
static df_iterator begin(const GraphT &G, SetType &S)
reference operator*() const
std::ptrdiff_t difference_type
typename GT::NodeRef value_type
A range adaptor for a pair of iterators.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
This is an optimization pass for GlobalISel generic memory operations.
iterator_range< df_ext_iterator< T, SetTy > > depth_first_ext(const T &G, SetTy &S)
idf_ext_iterator< T, SetTy > idf_ext_end(const T &G, SetTy &S)
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
df_iterator< T > df_begin(const T &G)
idf_ext_iterator< T, SetTy > idf_ext_begin(const T &G, SetTy &S)
iterator_range< idf_iterator< T > > inverse_depth_first(const T &G)
df_ext_iterator< T, SetTy > df_ext_begin(const T &G, SetTy &S)
idf_iterator< T > idf_end(const T &G)
iterator_range< idf_ext_iterator< T, SetTy > > inverse_depth_first_ext(const T &G, SetTy &S)
FunctionAddr VTableAddr Next
Definition InstrProf.h:141
idf_iterator< T > idf_begin(const T &G)
df_ext_iterator< T, SetTy > df_ext_end(const T &G, SetTy &S)
df_iterator< T > df_end(const T &G)
iterator_range< df_iterator< T > > depth_first(const T &G)
#define N
df_ext_iterator(const df_iterator< T, SetTy, true > &V)
void insert(IterT Begin, IterT End)
typename BaseSet::iterator iterator
SmallPtrSet< NodeRef, SmallSize > BaseSet
std::pair< iterator, bool > insert(NodeRef N)
idf_ext_iterator(const idf_iterator< T, SetTy, true > &V)
idf_ext_iterator(const df_iterator< Inverse< T >, SetTy, true > &V)
idf_iterator(const df_iterator< Inverse< T >, SetTy, External > &V)