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