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