xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ADT/SetVector.h (revision 59c8e88e72633afbc47a4ace0d2170d00d51f7dc)
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(*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