]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/include/llvm/ADT/PriorityWorklist.h
Merge ^/head r319801 through r320041.
[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/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>>
57 class PriorityWorklist {
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
155   LLVM_NODISCARD T pop_back_val() {
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>
257 class SmallPriorityWorklist
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