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