xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ADT/SetVector.h (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
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 // This file implements a set that has insertion order iteration
10 // characteristics. This is useful for keeping a set of things that need to be
11 // visited later but in a deterministic order (insertion order). The interface
12 // is purposefully minimal.
13 //
14 // This file defines SetVector and SmallSetVector, which performs no allocations
15 // if the SetVector has less than a certain number of elements.
16 //
17 //===----------------------------------------------------------------------===//
18 
19 #ifndef LLVM_ADT_SETVECTOR_H
20 #define LLVM_ADT_SETVECTOR_H
21 
22 #include "llvm/ADT/ArrayRef.h"
23 #include "llvm/ADT/DenseSet.h"
24 #include "llvm/ADT/STLExtras.h"
25 #include "llvm/Support/Compiler.h"
26 #include <cassert>
27 #include <iterator>
28 #include <vector>
29 
30 namespace llvm {
31 
32 /// A vector that has set insertion semantics.
33 ///
34 /// This adapter class provides a way to keep a set of things that also has the
35 /// property of a deterministic iteration order. The order of iteration is the
36 /// order of insertion.
37 template <typename T, typename Vector = std::vector<T>,
38           typename Set = DenseSet<T>>
39 class SetVector {
40 public:
41   using value_type = T;
42   using key_type = T;
43   using reference = T&;
44   using const_reference = const T&;
45   using set_type = Set;
46   using vector_type = Vector;
47   using iterator = typename vector_type::const_iterator;
48   using const_iterator = typename vector_type::const_iterator;
49   using reverse_iterator = typename vector_type::const_reverse_iterator;
50   using const_reverse_iterator = typename vector_type::const_reverse_iterator;
51   using size_type = typename vector_type::size_type;
52 
53   /// Construct an empty SetVector
54   SetVector() = default;
55 
56   /// Initialize a SetVector with a range of elements
57   template<typename It>
58   SetVector(It Start, It End) {
59     insert(Start, End);
60   }
61 
62   ArrayRef<T> getArrayRef() const { return vector_; }
63 
64   /// Clear the SetVector and return the underlying vector.
65   Vector takeVector() {
66     set_.clear();
67     return std::move(vector_);
68   }
69 
70   /// Determine if the SetVector is empty or not.
71   bool empty() const {
72     return vector_.empty();
73   }
74 
75   /// Determine the number of elements in the SetVector.
76   size_type size() const {
77     return vector_.size();
78   }
79 
80   /// Get an iterator to the beginning of the SetVector.
81   iterator begin() {
82     return vector_.begin();
83   }
84 
85   /// Get a const_iterator to the beginning of the SetVector.
86   const_iterator begin() const {
87     return vector_.begin();
88   }
89 
90   /// Get an iterator to the end of the SetVector.
91   iterator end() {
92     return vector_.end();
93   }
94 
95   /// Get a const_iterator to the end of the SetVector.
96   const_iterator end() const {
97     return vector_.end();
98   }
99 
100   /// Get an reverse_iterator to the end of the SetVector.
101   reverse_iterator rbegin() {
102     return vector_.rbegin();
103   }
104 
105   /// Get a const_reverse_iterator to the end of the SetVector.
106   const_reverse_iterator rbegin() const {
107     return vector_.rbegin();
108   }
109 
110   /// Get a reverse_iterator to the beginning of the SetVector.
111   reverse_iterator rend() {
112     return vector_.rend();
113   }
114 
115   /// Get a const_reverse_iterator to the beginning of the SetVector.
116   const_reverse_iterator rend() const {
117     return vector_.rend();
118   }
119 
120   /// Return the first element of the SetVector.
121   const T &front() const {
122     assert(!empty() && "Cannot call front() on empty SetVector!");
123     return vector_.front();
124   }
125 
126   /// Return the last element of the SetVector.
127   const T &back() const {
128     assert(!empty() && "Cannot call back() on empty SetVector!");
129     return vector_.back();
130   }
131 
132   /// Index into the SetVector.
133   const_reference operator[](size_type n) const {
134     assert(n < vector_.size() && "SetVector access out of range!");
135     return vector_[n];
136   }
137 
138   /// Insert a new element into the SetVector.
139   /// \returns true if the element was inserted into the SetVector.
140   bool insert(const value_type &X) {
141     bool result = set_.insert(X).second;
142     if (result)
143       vector_.push_back(X);
144     return result;
145   }
146 
147   /// Insert a range of elements into the SetVector.
148   template<typename It>
149   void insert(It Start, It End) {
150     for (; Start != End; ++Start)
151       if (set_.insert(*Start).second)
152         vector_.push_back(*Start);
153   }
154 
155   /// Remove an item from the set vector.
156   bool remove(const value_type& X) {
157     if (set_.erase(X)) {
158       typename vector_type::iterator I = find(vector_, X);
159       assert(I != vector_.end() && "Corrupted SetVector instances!");
160       vector_.erase(I);
161       return true;
162     }
163     return false;
164   }
165 
166   /// Erase a single element from the set vector.
167   /// \returns an iterator pointing to the next element that followed the
168   /// element erased. This is the end of the SetVector if the last element is
169   /// erased.
170   iterator erase(iterator I) {
171     const key_type &V = *I;
172     assert(set_.count(V) && "Corrupted SetVector instances!");
173     set_.erase(V);
174 
175     // FIXME: No need to use the non-const iterator when built with
176     // std::vector.erase(const_iterator) as defined in C++11. This is for
177     // compatibility with non-standard libstdc++ up to 4.8 (fixed in 4.9).
178     auto NI = vector_.begin();
179     std::advance(NI, std::distance<iterator>(NI, I));
180 
181     return vector_.erase(NI);
182   }
183 
184   /// Remove items from the set vector based on a predicate function.
185   ///
186   /// This is intended to be equivalent to the following code, if we could
187   /// write it:
188   ///
189   /// \code
190   ///   V.erase(remove_if(V, P), V.end());
191   /// \endcode
192   ///
193   /// However, SetVector doesn't expose non-const iterators, making any
194   /// algorithm like remove_if impossible to use.
195   ///
196   /// \returns true if any element is removed.
197   template <typename UnaryPredicate>
198   bool remove_if(UnaryPredicate P) {
199     typename vector_type::iterator I =
200         llvm::remove_if(vector_, TestAndEraseFromSet<UnaryPredicate>(P, set_));
201     if (I == vector_.end())
202       return false;
203     vector_.erase(I, vector_.end());
204     return true;
205   }
206 
207   /// Check if the SetVector contains the given key.
208   bool contains(const key_type &key) const {
209     return set_.find(key) != set_.end();
210   }
211 
212   /// Count the number of elements of a given key in the SetVector.
213   /// \returns 0 if the element is not in the SetVector, 1 if it is.
214   size_type count(const key_type &key) const {
215     return set_.count(key);
216   }
217 
218   /// Completely clear the SetVector
219   void clear() {
220     set_.clear();
221     vector_.clear();
222   }
223 
224   /// Remove the last element of the SetVector.
225   void pop_back() {
226     assert(!empty() && "Cannot remove an element from an empty SetVector!");
227     set_.erase(back());
228     vector_.pop_back();
229   }
230 
231   LLVM_NODISCARD T pop_back_val() {
232     T Ret = back();
233     pop_back();
234     return Ret;
235   }
236 
237   bool operator==(const SetVector &that) const {
238     return vector_ == that.vector_;
239   }
240 
241   bool operator!=(const SetVector &that) const {
242     return vector_ != that.vector_;
243   }
244 
245   /// Compute This := This u S, return whether 'This' changed.
246   /// TODO: We should be able to use set_union from SetOperations.h, but
247   ///       SetVector interface is inconsistent with DenseSet.
248   template <class STy>
249   bool set_union(const STy &S) {
250     bool Changed = false;
251 
252     for (typename STy::const_iterator SI = S.begin(), SE = S.end(); SI != SE;
253          ++SI)
254       if (insert(*SI))
255         Changed = true;
256 
257     return Changed;
258   }
259 
260   /// Compute This := This - B
261   /// TODO: We should be able to use set_subtract from SetOperations.h, but
262   ///       SetVector interface is inconsistent with DenseSet.
263   template <class STy>
264   void set_subtract(const STy &S) {
265     for (typename STy::const_iterator SI = S.begin(), SE = S.end(); SI != SE;
266          ++SI)
267       remove(*SI);
268   }
269 
270   void swap(SetVector<T, Vector, Set> &RHS) {
271     set_.swap(RHS.set_);
272     vector_.swap(RHS.vector_);
273   }
274 
275 private:
276   /// A wrapper predicate designed for use with std::remove_if.
277   ///
278   /// This predicate wraps a predicate suitable for use with std::remove_if to
279   /// call set_.erase(x) on each element which is slated for removal.
280   template <typename UnaryPredicate>
281   class TestAndEraseFromSet {
282     UnaryPredicate P;
283     set_type &set_;
284 
285   public:
286     TestAndEraseFromSet(UnaryPredicate P, set_type &set_)
287         : P(std::move(P)), set_(set_) {}
288 
289     template <typename ArgumentT>
290     bool operator()(const ArgumentT &Arg) {
291       if (P(Arg)) {
292         set_.erase(Arg);
293         return true;
294       }
295       return false;
296     }
297   };
298 
299   set_type set_;         ///< The set.
300   vector_type vector_;   ///< The vector.
301 };
302 
303 /// A SetVector that performs no allocations if smaller than
304 /// a certain size.
305 template <typename T, unsigned N>
306 class SmallSetVector
307     : public SetVector<T, SmallVector<T, N>, SmallDenseSet<T, N>> {
308 public:
309   SmallSetVector() = default;
310 
311   /// Initialize a SmallSetVector with a range of elements
312   template<typename It>
313   SmallSetVector(It Start, It End) {
314     this->insert(Start, End);
315   }
316 };
317 
318 } // end namespace llvm
319 
320 namespace std {
321 
322 /// Implement std::swap in terms of SetVector swap.
323 template<typename T, typename V, typename S>
324 inline void
325 swap(llvm::SetVector<T, V, S> &LHS, llvm::SetVector<T, V, S> &RHS) {
326   LHS.swap(RHS);
327 }
328 
329 /// Implement std::swap in terms of SmallSetVector swap.
330 template<typename T, unsigned N>
331 inline void
332 swap(llvm::SmallSetVector<T, N> &LHS, llvm::SmallSetVector<T, N> &RHS) {
333   LHS.swap(RHS);
334 }
335 
336 } // end namespace std
337 
338 #endif // LLVM_ADT_SETVECTOR_H
339