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> 82 SetVector(It Start, It End) { 83 insert(Start, End); 84 } 85 86 template <typename Range> 87 SetVector(llvm::from_range_t, Range &&R) 88 : SetVector(adl_begin(R), adl_end(R)) {} 89 90 ArrayRef<value_type> getArrayRef() const { return vector_; } 91 92 /// Clear the SetVector and return the underlying vector. 93 Vector takeVector() { 94 set_.clear(); 95 return std::move(vector_); 96 } 97 98 /// Determine if the SetVector is empty or not. 99 bool empty() const { 100 return vector_.empty(); 101 } 102 103 /// Determine the number of elements in the SetVector. 104 size_type size() const { 105 return vector_.size(); 106 } 107 108 /// Get an iterator to the beginning of the SetVector. 109 iterator begin() { 110 return vector_.begin(); 111 } 112 113 /// Get a const_iterator to the beginning of the SetVector. 114 const_iterator begin() const { 115 return vector_.begin(); 116 } 117 118 /// Get an iterator to the end of the SetVector. 119 iterator end() { 120 return vector_.end(); 121 } 122 123 /// Get a const_iterator to the end of the SetVector. 124 const_iterator end() const { 125 return vector_.end(); 126 } 127 128 /// Get an reverse_iterator to the end of the SetVector. 129 reverse_iterator rbegin() { 130 return vector_.rbegin(); 131 } 132 133 /// Get a const_reverse_iterator to the end of the SetVector. 134 const_reverse_iterator rbegin() const { 135 return vector_.rbegin(); 136 } 137 138 /// Get a reverse_iterator to the beginning of the SetVector. 139 reverse_iterator rend() { 140 return vector_.rend(); 141 } 142 143 /// Get a const_reverse_iterator to the beginning of the SetVector. 144 const_reverse_iterator rend() const { 145 return vector_.rend(); 146 } 147 148 /// Return the first element of the SetVector. 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. 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. 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> 188 void insert(It Start, It End) { 189 for (; Start != End; ++Start) 190 insert(*Start); 191 } 192 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. 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. 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> 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. 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. 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 283 void clear() { 284 set_.clear(); 285 vector_.clear(); 286 } 287 288 /// Remove the last element of the SetVector. 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 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> 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> 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 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: 350 TestAndEraseFromSet(UnaryPredicate P, set_type &set_) 351 : P(std::move(P)), set_(set_) {} 352 353 template <typename ArgumentT> 354 bool operator()(const ArgumentT &Arg) { 355 if (P(Arg)) { 356 set_.erase(Arg); 357 return true; 358 } 359 return false; 360 } 361 }; 362 363 [[nodiscard]] static constexpr bool canBeSmall() { return N != 0; } 364 365 [[nodiscard]] bool isSmall() const { return set_.empty(); } 366 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> 386 SmallSetVector(It Start, It End) { 387 this->insert(Start, End); 388 } 389 390 template <typename Range> 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> 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 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