LLVM  8.0.1
PriorityWorklist.h
Go to the documentation of this file.
1 //===- PriorityWorklist.h - Worklist with insertion priority ----*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 ///
12 /// This file provides a priority worklist. See the class comments for details.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #ifndef LLVM_ADT_PRIORITYWORKLIST_H
17 #define LLVM_ADT_PRIORITYWORKLIST_H
18 
19 #include "llvm/ADT/DenseMap.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/Support/Compiler.h"
23 #include <algorithm>
24 #include <cassert>
25 #include <cstddef>
26 #include <iterator>
27 #include <type_traits>
28 #include <vector>
29 
30 namespace llvm {
31 
32 /// A FILO worklist that prioritizes on re-insertion without duplication.
33 ///
34 /// This is very similar to a \c SetVector with the primary difference that
35 /// while re-insertion does not create a duplicate, it does adjust the
36 /// visitation order to respect the last insertion point. This can be useful
37 /// when the visit order needs to be prioritized based on insertion point
38 /// without actually having duplicate visits.
39 ///
40 /// Note that this doesn't prevent re-insertion of elements which have been
41 /// visited -- if you need to break cycles, a set will still be necessary.
42 ///
43 /// The type \c T must be default constructable to a null value that will be
44 /// ignored. It is an error to insert such a value, and popping elements will
45 /// never produce such a value. It is expected to be used with common nullable
46 /// types like pointers or optionals.
47 ///
48 /// Internally this uses a vector to store the worklist and a map to identify
49 /// existing elements in the worklist. Both of these may be customized, but the
50 /// map must support the basic DenseMap API for mapping from a T to an integer
51 /// index into the vector.
52 ///
53 /// A partial specialization is provided to automatically select a SmallVector
54 /// and a SmallDenseMap if custom data structures are not provided.
55 template <typename T, typename VectorT = std::vector<T>,
56  typename MapT = DenseMap<T, ptrdiff_t>>
58 public:
59  using value_type = T;
60  using key_type = T;
61  using reference = T&;
62  using const_reference = const T&;
63  using size_type = typename MapT::size_type;
64 
65  /// Construct an empty PriorityWorklist
66  PriorityWorklist() = default;
67 
68  /// Determine if the PriorityWorklist is empty or not.
69  bool empty() const {
70  return V.empty();
71  }
72 
73  /// Returns the number of elements in the worklist.
74  size_type size() const {
75  return M.size();
76  }
77 
78  /// Count the number of elements of a given key in the PriorityWorklist.
79  /// \returns 0 if the element is not in the PriorityWorklist, 1 if it is.
80  size_type count(const key_type &key) const {
81  return M.count(key);
82  }
83 
84  /// Return the last element of the PriorityWorklist.
85  const T &back() const {
86  assert(!empty() && "Cannot call back() on empty PriorityWorklist!");
87  return V.back();
88  }
89 
90  /// Insert a new element into the PriorityWorklist.
91  /// \returns true if the element was inserted into the PriorityWorklist.
92  bool insert(const T &X) {
93  assert(X != T() && "Cannot insert a null (default constructed) value!");
94  auto InsertResult = M.insert({X, V.size()});
95  if (InsertResult.second) {
96  // Fresh value, just append it to the vector.
97  V.push_back(X);
98  return true;
99  }
100 
101  auto &Index = InsertResult.first->second;
102  assert(V[Index] == X && "Value not actually at index in map!");
103  if (Index != (ptrdiff_t)(V.size() - 1)) {
104  // If the element isn't at the back, null it out and append a fresh one.
105  V[Index] = T();
106  Index = (ptrdiff_t)V.size();
107  V.push_back(X);
108  }
109  return false;
110  }
111 
112  /// Insert a sequence of new elements into the PriorityWorklist.
113  template <typename SequenceT>
114  typename std::enable_if<!std::is_convertible<SequenceT, T>::value>::type
115  insert(SequenceT &&Input) {
116  if (std::begin(Input) == std::end(Input))
117  // Nothing to do for an empty input sequence.
118  return;
119 
120  // First pull the input sequence into the vector as a bulk append
121  // operation.
122  ptrdiff_t StartIndex = V.size();
123  V.insert(V.end(), std::begin(Input), std::end(Input));
124  // Now walk backwards fixing up the index map and deleting any duplicates.
125  for (ptrdiff_t i = V.size() - 1; i >= StartIndex; --i) {
126  auto InsertResult = M.insert({V[i], i});
127  if (InsertResult.second)
128  continue;
129 
130  // If the existing index is before this insert's start, nuke that one and
131  // move it up.
132  ptrdiff_t &Index = InsertResult.first->second;
133  if (Index < StartIndex) {
134  V[Index] = T();
135  Index = i;
136  continue;
137  }
138 
139  // Otherwise the existing one comes first so just clear out the value in
140  // this slot.
141  V[i] = T();
142  }
143  }
144 
145  /// Remove the last element of the PriorityWorklist.
146  void pop_back() {
147  assert(!empty() && "Cannot remove an element when empty!");
148  assert(back() != T() && "Cannot have a null element at the back!");
149  M.erase(back());
150  do {
151  V.pop_back();
152  } while (!V.empty() && V.back() == T());
153  }
154 
156  T Ret = back();
157  pop_back();
158  return Ret;
159  }
160 
161  /// Erase an item from the worklist.
162  ///
163  /// Note that this is constant time due to the nature of the worklist implementation.
164  bool erase(const T& X) {
165  auto I = M.find(X);
166  if (I == M.end())
167  return false;
168 
169  assert(V[I->second] == X && "Value not actually at index in map!");
170  if (I->second == (ptrdiff_t)(V.size() - 1)) {
171  do {
172  V.pop_back();
173  } while (!V.empty() && V.back() == T());
174  } else {
175  V[I->second] = T();
176  }
177  M.erase(I);
178  return true;
179  }
180 
181  /// Erase items from the set vector based on a predicate function.
182  ///
183  /// This is intended to be equivalent to the following code, if we could
184  /// write it:
185  ///
186  /// \code
187  /// V.erase(remove_if(V, P), V.end());
188  /// \endcode
189  ///
190  /// However, PriorityWorklist doesn't expose non-const iterators, making any
191  /// algorithm like remove_if impossible to use.
192  ///
193  /// \returns true if any element is removed.
194  template <typename UnaryPredicate>
195  bool erase_if(UnaryPredicate P) {
196  typename VectorT::iterator E =
197  remove_if(V, TestAndEraseFromMap<UnaryPredicate>(P, M));
198  if (E == V.end())
199  return false;
200  for (auto I = V.begin(); I != E; ++I)
201  if (*I != T())
202  M[*I] = I - V.begin();
203  V.erase(E, V.end());
204  return true;
205  }
206 
207  /// Reverse the items in the PriorityWorklist.
208  ///
209  /// This does an in-place reversal. Other kinds of reverse aren't easy to
210  /// support in the face of the worklist semantics.
211 
212  /// Completely clear the PriorityWorklist
213  void clear() {
214  M.clear();
215  V.clear();
216  }
217 
218 private:
219  /// A wrapper predicate designed for use with std::remove_if.
220  ///
221  /// This predicate wraps a predicate suitable for use with std::remove_if to
222  /// call M.erase(x) on each element which is slated for removal. This just
223  /// allows the predicate to be move only which we can't do with lambdas
224  /// today.
225  template <typename UnaryPredicateT>
226  class TestAndEraseFromMap {
227  UnaryPredicateT P;
228  MapT &M;
229 
230  public:
231  TestAndEraseFromMap(UnaryPredicateT P, MapT &M)
232  : P(std::move(P)), M(M) {}
233 
234  bool operator()(const T &Arg) {
235  if (Arg == T())
236  // Skip null values in the PriorityWorklist.
237  return false;
238 
239  if (P(Arg)) {
240  M.erase(Arg);
241  return true;
242  }
243  return false;
244  }
245  };
246 
247  /// The map from value to index in the vector.
248  MapT M;
249 
250  /// The vector of elements in insertion order.
251  VectorT V;
252 };
253 
254 /// A version of \c PriorityWorklist that selects small size optimized data
255 /// structures for the vector and map.
256 template <typename T, unsigned N>
258  : public PriorityWorklist<T, SmallVector<T, N>,
259  SmallDenseMap<T, ptrdiff_t>> {
260 public:
261  SmallPriorityWorklist() = default;
262 };
263 
264 } // end namespace llvm
265 
266 #endif // LLVM_ADT_PRIORITYWORKLIST_H
const_iterator end(StringRef path)
Get end iterator over path.
Definition: Path.cpp:259
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
bool erase(const T &X)
Erase an item from the worklist.
bool insert(const T &X)
Insert a new element into the PriorityWorklist.
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
Definition: Path.cpp:250
This class represents lattice values for constants.
Definition: AllocatorList.h:24
LLVM_NODISCARD T pop_back_val()
bool erase_if(UnaryPredicate P)
Erase items from the set vector based on a predicate function.
size_type size() const
Returns the number of elements in the worklist.
bool empty() const
Determine if the PriorityWorklist is empty or not.
PriorityWorklist()=default
Construct an empty PriorityWorklist.
const T & back() const
Return the last element of the PriorityWorklist.
#define LLVM_NODISCARD
LLVM_NODISCARD - Warn if a type or return value is discarded.
Definition: Compiler.h:129
#define T
#define P(N)
void clear()
Reverse the items in the PriorityWorklist.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
size_type count(const key_type &key) const
Count the number of elements of a given key in the PriorityWorklist.
std::enable_if<!std::is_convertible< SequenceT, T >::value >::type insert(SequenceT &&Input)
Insert a sequence of new elements into the PriorityWorklist.
A version of PriorityWorklist that selects small size optimized data structures for the vector and ma...
A FILO worklist that prioritizes on re-insertion without duplication.
auto remove_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range))
Provide wrappers to std::remove_if which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:1226
amdgpu Simplify well known AMD library false Value Value * Arg
#define I(x, y, z)
Definition: MD5.cpp:58
void pop_back()
Remove the last element of the PriorityWorklist.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
An SCC of the call graph.