1 | //===- llvm/ADT/SetVector.h - Set with insert order iteration ---*- 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 implements a set that has insertion order iteration |
11 | /// characteristics. This is useful for keeping a set of things that need to be |
12 | /// visited later but in a deterministic order (insertion order). The interface |
13 | /// is purposefully minimal. |
14 | /// |
15 | /// This file defines SetVector and SmallSetVector, which performs no |
16 | /// allocations if the SetVector has less than a certain number of elements. |
17 | /// |
18 | //===----------------------------------------------------------------------===// |
19 | |
20 | #ifndef LLVM_ADT_SETVECTOR_H |
21 | #define LLVM_ADT_SETVECTOR_H |
22 | |
23 | #include "llvm/ADT/ArrayRef.h" |
24 | #include "llvm/ADT/DenseSet.h" |
25 | #include "llvm/ADT/STLExtras.h" |
26 | #include "llvm/Support/Compiler.h" |
27 | #include <cassert> |
28 | #include <iterator> |
29 | #include <vector> |
30 | |
31 | namespace llvm { |
32 | |
33 | /// A vector that has set insertion semantics. |
34 | /// |
35 | /// This adapter class provides a way to keep a set of things that also has the |
36 | /// property of a deterministic iteration order. The order of iteration is the |
37 | /// order of insertion. |
38 | /// |
39 | /// The key and value types are derived from the Set and Vector types |
40 | /// respectively. This allows the vector-type operations and set-type operations |
41 | /// to have different types. In particular, this is useful when storing pointers |
42 | /// as "Foo *" values but looking them up as "const Foo *" keys. |
43 | /// |
44 | /// No constraint is placed on the key and value types, although it is assumed |
45 | /// that value_type can be converted into key_type for insertion. Users must be |
46 | /// aware of any loss of information in this conversion. For example, setting |
47 | /// value_type to float and key_type to int can produce very surprising results, |
48 | /// but it is not explicitly disallowed. |
49 | /// |
50 | /// The parameter N specifies the "small" size of the container, which is the |
51 | /// number of elements upto which a linear scan over the Vector will be used |
52 | /// when searching for elements instead of checking Set, due to it being better |
53 | /// for performance. A value of 0 means that this mode of operation is not used, |
54 | /// and is the default value. |
55 | template <typename T, typename Vector = std::vector<T>, |
56 | typename Set = DenseSet<T>, unsigned N = 0> |
57 | class SetVector { |
58 | // Much like in SmallPtrSet, this value should not be too high to prevent |
59 | // excessively long linear scans from occuring. |
60 | static_assert(N <= 32, "Small size should be less than or equal to 32!" ); |
61 | |
62 | public: |
63 | using value_type = typename Vector::value_type; |
64 | using key_type = typename Set::key_type; |
65 | using reference = value_type &; |
66 | using const_reference = const value_type &; |
67 | using set_type = Set; |
68 | using vector_type = Vector; |
69 | using iterator = typename vector_type::const_iterator; |
70 | using const_iterator = typename vector_type::const_iterator; |
71 | using reverse_iterator = typename vector_type::const_reverse_iterator; |
72 | using const_reverse_iterator = typename vector_type::const_reverse_iterator; |
73 | using size_type = typename vector_type::size_type; |
74 | |
75 | /// Construct an empty SetVector |
76 | SetVector() = default; |
77 | |
78 | /// Initialize a SetVector with a range of elements |
79 | template<typename It> |
80 | SetVector(It Start, It End) { |
81 | insert(Start, End); |
82 | } |
83 | |
84 | ArrayRef<value_type> getArrayRef() const { return vector_; } |
85 | |
86 | /// Clear the SetVector and return the underlying vector. |
87 | Vector takeVector() { |
88 | set_.clear(); |
89 | return std::move(vector_); |
90 | } |
91 | |
92 | /// Determine if the SetVector is empty or not. |
93 | bool empty() const { |
94 | return vector_.empty(); |
95 | } |
96 | |
97 | /// Determine the number of elements in the SetVector. |
98 | size_type size() const { |
99 | return vector_.size(); |
100 | } |
101 | |
102 | /// Get an iterator to the beginning of the SetVector. |
103 | iterator begin() { |
104 | return vector_.begin(); |
105 | } |
106 | |
107 | /// Get a const_iterator to the beginning of the SetVector. |
108 | const_iterator begin() const { |
109 | return vector_.begin(); |
110 | } |
111 | |
112 | /// Get an iterator to the end of the SetVector. |
113 | iterator end() { |
114 | return vector_.end(); |
115 | } |
116 | |
117 | /// Get a const_iterator to the end of the SetVector. |
118 | const_iterator end() const { |
119 | return vector_.end(); |
120 | } |
121 | |
122 | /// Get an reverse_iterator to the end of the SetVector. |
123 | reverse_iterator rbegin() { |
124 | return vector_.rbegin(); |
125 | } |
126 | |
127 | /// Get a const_reverse_iterator to the end of the SetVector. |
128 | const_reverse_iterator rbegin() const { |
129 | return vector_.rbegin(); |
130 | } |
131 | |
132 | /// Get a reverse_iterator to the beginning of the SetVector. |
133 | reverse_iterator rend() { |
134 | return vector_.rend(); |
135 | } |
136 | |
137 | /// Get a const_reverse_iterator to the beginning of the SetVector. |
138 | const_reverse_iterator rend() const { |
139 | return vector_.rend(); |
140 | } |
141 | |
142 | /// Return the first element of the SetVector. |
143 | const value_type &front() const { |
144 | assert(!empty() && "Cannot call front() on empty SetVector!" ); |
145 | return vector_.front(); |
146 | } |
147 | |
148 | /// Return the last element of the SetVector. |
149 | const value_type &back() const { |
150 | assert(!empty() && "Cannot call back() on empty SetVector!" ); |
151 | return vector_.back(); |
152 | } |
153 | |
154 | /// Index into the SetVector. |
155 | const_reference operator[](size_type n) const { |
156 | assert(n < vector_.size() && "SetVector access out of range!" ); |
157 | return vector_[n]; |
158 | } |
159 | |
160 | /// Insert a new element into the SetVector. |
161 | /// \returns true if the element was inserted into the SetVector. |
162 | bool insert(const value_type &X) { |
163 | if constexpr (canBeSmall()) |
164 | if (isSmall()) { |
165 | if (llvm::find(vector_, X) == vector_.end()) { |
166 | vector_.push_back(X); |
167 | if (vector_.size() > N) |
168 | makeBig(); |
169 | return true; |
170 | } |
171 | return false; |
172 | } |
173 | |
174 | bool result = set_.insert(X).second; |
175 | if (result) |
176 | vector_.push_back(X); |
177 | return result; |
178 | } |
179 | |
180 | /// Insert a range of elements into the SetVector. |
181 | template<typename It> |
182 | void insert(It Start, It End) { |
183 | for (; Start != End; ++Start) |
184 | insert(*Start); |
185 | } |
186 | |
187 | /// Remove an item from the set vector. |
188 | bool remove(const value_type& X) { |
189 | if constexpr (canBeSmall()) |
190 | if (isSmall()) { |
191 | typename vector_type::iterator I = find(vector_, X); |
192 | if (I != vector_.end()) { |
193 | vector_.erase(I); |
194 | return true; |
195 | } |
196 | return false; |
197 | } |
198 | |
199 | if (set_.erase(X)) { |
200 | typename vector_type::iterator I = find(vector_, X); |
201 | assert(I != vector_.end() && "Corrupted SetVector instances!" ); |
202 | vector_.erase(I); |
203 | return true; |
204 | } |
205 | return false; |
206 | } |
207 | |
208 | /// Erase a single element from the set vector. |
209 | /// \returns an iterator pointing to the next element that followed the |
210 | /// element erased. This is the end of the SetVector if the last element is |
211 | /// erased. |
212 | iterator erase(const_iterator I) { |
213 | if constexpr (canBeSmall()) |
214 | if (isSmall()) |
215 | return vector_.erase(I); |
216 | |
217 | const key_type &V = *I; |
218 | assert(set_.count(V) && "Corrupted SetVector instances!" ); |
219 | set_.erase(V); |
220 | return vector_.erase(I); |
221 | } |
222 | |
223 | /// Remove items from the set vector based on a predicate function. |
224 | /// |
225 | /// This is intended to be equivalent to the following code, if we could |
226 | /// write it: |
227 | /// |
228 | /// \code |
229 | /// V.erase(remove_if(V, P), V.end()); |
230 | /// \endcode |
231 | /// |
232 | /// However, SetVector doesn't expose non-const iterators, making any |
233 | /// algorithm like remove_if impossible to use. |
234 | /// |
235 | /// \returns true if any element is removed. |
236 | template <typename UnaryPredicate> |
237 | bool remove_if(UnaryPredicate P) { |
238 | typename vector_type::iterator I = [this, P] { |
239 | if constexpr (canBeSmall()) |
240 | if (isSmall()) |
241 | return llvm::remove_if(vector_, P); |
242 | |
243 | return llvm::remove_if(vector_, |
244 | TestAndEraseFromSet<UnaryPredicate>(P, set_)); |
245 | }(); |
246 | |
247 | if (I == vector_.end()) |
248 | return false; |
249 | vector_.erase(I, vector_.end()); |
250 | return true; |
251 | } |
252 | |
253 | /// Check if the SetVector contains the given key. |
254 | bool contains(const key_type &key) const { |
255 | if constexpr (canBeSmall()) |
256 | if (isSmall()) |
257 | return is_contained(vector_, key); |
258 | |
259 | return set_.find(key) != set_.end(); |
260 | } |
261 | |
262 | /// Count the number of elements of a given key in the SetVector. |
263 | /// \returns 0 if the element is not in the SetVector, 1 if it is. |
264 | size_type count(const key_type &key) const { |
265 | if constexpr (canBeSmall()) |
266 | if (isSmall()) |
267 | return is_contained(vector_, key); |
268 | |
269 | return set_.count(key); |
270 | } |
271 | |
272 | /// Completely clear the SetVector |
273 | void clear() { |
274 | set_.clear(); |
275 | vector_.clear(); |
276 | } |
277 | |
278 | /// Remove the last element of the SetVector. |
279 | void pop_back() { |
280 | assert(!empty() && "Cannot remove an element from an empty SetVector!" ); |
281 | set_.erase(back()); |
282 | vector_.pop_back(); |
283 | } |
284 | |
285 | [[nodiscard]] value_type pop_back_val() { |
286 | value_type Ret = back(); |
287 | pop_back(); |
288 | return Ret; |
289 | } |
290 | |
291 | bool operator==(const SetVector &that) const { |
292 | return vector_ == that.vector_; |
293 | } |
294 | |
295 | bool operator!=(const SetVector &that) const { |
296 | return vector_ != that.vector_; |
297 | } |
298 | |
299 | /// Compute This := This u S, return whether 'This' changed. |
300 | /// TODO: We should be able to use set_union from SetOperations.h, but |
301 | /// SetVector interface is inconsistent with DenseSet. |
302 | template <class STy> |
303 | bool set_union(const STy &S) { |
304 | bool Changed = false; |
305 | |
306 | for (typename STy::const_iterator SI = S.begin(), SE = S.end(); SI != SE; |
307 | ++SI) |
308 | if (insert(*SI)) |
309 | Changed = true; |
310 | |
311 | return Changed; |
312 | } |
313 | |
314 | /// Compute This := This - B |
315 | /// TODO: We should be able to use set_subtract from SetOperations.h, but |
316 | /// SetVector interface is inconsistent with DenseSet. |
317 | template <class STy> |
318 | void set_subtract(const STy &S) { |
319 | for (typename STy::const_iterator SI = S.begin(), SE = S.end(); SI != SE; |
320 | ++SI) |
321 | remove(X: *SI); |
322 | } |
323 | |
324 | void swap(SetVector<T, Vector, Set, N> &RHS) { |
325 | set_.swap(RHS.set_); |
326 | vector_.swap(RHS.vector_); |
327 | } |
328 | |
329 | private: |
330 | /// A wrapper predicate designed for use with std::remove_if. |
331 | /// |
332 | /// This predicate wraps a predicate suitable for use with std::remove_if to |
333 | /// call set_.erase(x) on each element which is slated for removal. |
334 | template <typename UnaryPredicate> |
335 | class TestAndEraseFromSet { |
336 | UnaryPredicate P; |
337 | set_type &set_; |
338 | |
339 | public: |
340 | TestAndEraseFromSet(UnaryPredicate P, set_type &set_) |
341 | : P(std::move(P)), set_(set_) {} |
342 | |
343 | template <typename ArgumentT> |
344 | bool operator()(const ArgumentT &Arg) { |
345 | if (P(Arg)) { |
346 | set_.erase(Arg); |
347 | return true; |
348 | } |
349 | return false; |
350 | } |
351 | }; |
352 | |
353 | [[nodiscard]] static constexpr bool canBeSmall() { return N != 0; } |
354 | |
355 | [[nodiscard]] bool isSmall() const { return set_.empty(); } |
356 | |
357 | void makeBig() { |
358 | if constexpr (canBeSmall()) |
359 | for (const auto &entry : vector_) |
360 | set_.insert(entry); |
361 | } |
362 | |
363 | set_type set_; ///< The set. |
364 | vector_type vector_; ///< The vector. |
365 | }; |
366 | |
367 | /// A SetVector that performs no allocations if smaller than |
368 | /// a certain size. |
369 | template <typename T, unsigned N> |
370 | class SmallSetVector : public SetVector<T, SmallVector<T, N>, DenseSet<T>, N> { |
371 | public: |
372 | SmallSetVector() = default; |
373 | |
374 | /// Initialize a SmallSetVector with a range of elements |
375 | template<typename It> |
376 | SmallSetVector(It Start, It End) { |
377 | this->insert(Start, End); |
378 | } |
379 | }; |
380 | |
381 | } // end namespace llvm |
382 | |
383 | namespace std { |
384 | |
385 | /// Implement std::swap in terms of SetVector swap. |
386 | template <typename T, typename V, typename S, unsigned N> |
387 | inline void swap(llvm::SetVector<T, V, S, N> &LHS, |
388 | llvm::SetVector<T, V, S, N> &RHS) { |
389 | LHS.swap(RHS); |
390 | } |
391 | |
392 | /// Implement std::swap in terms of SmallSetVector swap. |
393 | template<typename T, unsigned N> |
394 | inline void |
395 | swap(llvm::SmallSetVector<T, N> &LHS, llvm::SmallSetVector<T, N> &RHS) { |
396 | LHS.swap(RHS); |
397 | } |
398 | |
399 | } // end namespace std |
400 | |
401 | #endif // LLVM_ADT_SETVECTOR_H |
402 | |