SmallSet.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. ///
  14. /// \file
  15. /// This file defines the SmallSet class.
  16. ///
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_ADT_SMALLSET_H
  19. #define LLVM_ADT_SMALLSET_H
  20. #include "llvm/ADT/SmallPtrSet.h"
  21. #include "llvm/ADT/SmallVector.h"
  22. #include "llvm/ADT/STLExtras.h"
  23. #include "llvm/ADT/iterator.h"
  24. #include "llvm/Support/Compiler.h"
  25. #include "llvm/Support/type_traits.h"
  26. #include <cstddef>
  27. #include <functional>
  28. #include <set>
  29. #include <type_traits>
  30. #include <utility>
  31. namespace llvm {
  32. /// SmallSetIterator - This class implements a const_iterator for SmallSet by
  33. /// delegating to the underlying SmallVector or Set iterators.
  34. template <typename T, unsigned N, typename C>
  35. class SmallSetIterator
  36. : public iterator_facade_base<SmallSetIterator<T, N, C>,
  37. std::forward_iterator_tag, T> {
  38. private:
  39. using SetIterTy = typename std::set<T, C>::const_iterator;
  40. using VecIterTy = typename SmallVector<T, N>::const_iterator;
  41. using SelfTy = SmallSetIterator<T, N, C>;
  42. /// Iterators to the parts of the SmallSet containing the data. They are set
  43. /// depending on isSmall.
  44. union {
  45. SetIterTy SetIter;
  46. VecIterTy VecIter;
  47. };
  48. bool isSmall;
  49. public:
  50. SmallSetIterator(SetIterTy SetIter) : SetIter(SetIter), isSmall(false) {}
  51. SmallSetIterator(VecIterTy VecIter) : VecIter(VecIter), isSmall(true) {}
  52. // Spell out destructor, copy/move constructor and assignment operators for
  53. // MSVC STL, where set<T>::const_iterator is not trivially copy constructible.
  54. ~SmallSetIterator() {
  55. if (isSmall)
  56. VecIter.~VecIterTy();
  57. else
  58. SetIter.~SetIterTy();
  59. }
  60. SmallSetIterator(const SmallSetIterator &Other) : isSmall(Other.isSmall) {
  61. if (isSmall)
  62. VecIter = Other.VecIter;
  63. else
  64. // Use placement new, to make sure SetIter is properly constructed, even
  65. // if it is not trivially copy-able (e.g. in MSVC).
  66. new (&SetIter) SetIterTy(Other.SetIter);
  67. }
  68. SmallSetIterator(SmallSetIterator &&Other) : isSmall(Other.isSmall) {
  69. if (isSmall)
  70. VecIter = std::move(Other.VecIter);
  71. else
  72. // Use placement new, to make sure SetIter is properly constructed, even
  73. // if it is not trivially copy-able (e.g. in MSVC).
  74. new (&SetIter) SetIterTy(std::move(Other.SetIter));
  75. }
  76. SmallSetIterator& operator=(const SmallSetIterator& Other) {
  77. // Call destructor for SetIter, so it gets properly destroyed if it is
  78. // not trivially destructible in case we are setting VecIter.
  79. if (!isSmall)
  80. SetIter.~SetIterTy();
  81. isSmall = Other.isSmall;
  82. if (isSmall)
  83. VecIter = Other.VecIter;
  84. else
  85. new (&SetIter) SetIterTy(Other.SetIter);
  86. return *this;
  87. }
  88. SmallSetIterator& operator=(SmallSetIterator&& Other) {
  89. // Call destructor for SetIter, so it gets properly destroyed if it is
  90. // not trivially destructible in case we are setting VecIter.
  91. if (!isSmall)
  92. SetIter.~SetIterTy();
  93. isSmall = Other.isSmall;
  94. if (isSmall)
  95. VecIter = std::move(Other.VecIter);
  96. else
  97. new (&SetIter) SetIterTy(std::move(Other.SetIter));
  98. return *this;
  99. }
  100. bool operator==(const SmallSetIterator &RHS) const {
  101. if (isSmall != RHS.isSmall)
  102. return false;
  103. if (isSmall)
  104. return VecIter == RHS.VecIter;
  105. return SetIter == RHS.SetIter;
  106. }
  107. SmallSetIterator &operator++() { // Preincrement
  108. if (isSmall)
  109. VecIter++;
  110. else
  111. SetIter++;
  112. return *this;
  113. }
  114. const T &operator*() const { return isSmall ? *VecIter : *SetIter; }
  115. };
  116. /// SmallSet - This maintains a set of unique values, optimizing for the case
  117. /// when the set is small (less than N). In this case, the set can be
  118. /// maintained with no mallocs. If the set gets large, we expand to using an
  119. /// std::set to maintain reasonable lookup times.
  120. template <typename T, unsigned N, typename C = std::less<T>>
  121. class SmallSet {
  122. /// Use a SmallVector to hold the elements here (even though it will never
  123. /// reach its 'large' stage) to avoid calling the default ctors of elements
  124. /// we will never use.
  125. SmallVector<T, N> Vector;
  126. std::set<T, C> Set;
  127. using VIterator = typename SmallVector<T, N>::const_iterator;
  128. using SIterator = typename std::set<T, C>::const_iterator;
  129. using mutable_iterator = typename SmallVector<T, N>::iterator;
  130. // In small mode SmallPtrSet uses linear search for the elements, so it is
  131. // not a good idea to choose this value too high. You may consider using a
  132. // DenseSet<> instead if you expect many elements in the set.
  133. static_assert(N <= 32, "N should be small");
  134. public:
  135. using size_type = size_t;
  136. using const_iterator = SmallSetIterator<T, N, C>;
  137. SmallSet() = default;
  138. [[nodiscard]] bool empty() const { return Vector.empty() && Set.empty(); }
  139. size_type size() const {
  140. return isSmall() ? Vector.size() : Set.size();
  141. }
  142. /// count - Return 1 if the element is in the set, 0 otherwise.
  143. size_type count(const T &V) const {
  144. if (isSmall()) {
  145. // Since the collection is small, just do a linear search.
  146. return vfind(V) == Vector.end() ? 0 : 1;
  147. } else {
  148. return Set.count(V);
  149. }
  150. }
  151. /// insert - Insert an element into the set if it isn't already there.
  152. /// Returns a pair. The first value of it is an iterator to the inserted
  153. /// element or the existing element in the set. The second value is true
  154. /// if the element is inserted (it was not in the set before).
  155. std::pair<const_iterator, bool> insert(const T &V) {
  156. if (!isSmall()) {
  157. auto [I, Inserted] = Set.insert(V);
  158. return std::make_pair(const_iterator(I), Inserted);
  159. }
  160. VIterator I = vfind(V);
  161. if (I != Vector.end()) // Don't reinsert if it already exists.
  162. return std::make_pair(const_iterator(I), false);
  163. if (Vector.size() < N) {
  164. Vector.push_back(V);
  165. return std::make_pair(const_iterator(std::prev(Vector.end())), true);
  166. }
  167. // Otherwise, grow from vector to set.
  168. while (!Vector.empty()) {
  169. Set.insert(Vector.back());
  170. Vector.pop_back();
  171. }
  172. return std::make_pair(const_iterator(Set.insert(V).first), true);
  173. }
  174. template <typename IterT>
  175. void insert(IterT I, IterT E) {
  176. for (; I != E; ++I)
  177. insert(*I);
  178. }
  179. bool erase(const T &V) {
  180. if (!isSmall())
  181. return Set.erase(V);
  182. for (mutable_iterator I = Vector.begin(), E = Vector.end(); I != E; ++I)
  183. if (*I == V) {
  184. Vector.erase(I);
  185. return true;
  186. }
  187. return false;
  188. }
  189. void clear() {
  190. Vector.clear();
  191. Set.clear();
  192. }
  193. const_iterator begin() const {
  194. if (isSmall())
  195. return {Vector.begin()};
  196. return {Set.begin()};
  197. }
  198. const_iterator end() const {
  199. if (isSmall())
  200. return {Vector.end()};
  201. return {Set.end()};
  202. }
  203. /// Check if the SmallSet contains the given element.
  204. bool contains(const T &V) const {
  205. if (isSmall())
  206. return vfind(V) != Vector.end();
  207. return Set.find(V) != Set.end();
  208. }
  209. private:
  210. bool isSmall() const { return Set.empty(); }
  211. VIterator vfind(const T &V) const {
  212. for (VIterator I = Vector.begin(), E = Vector.end(); I != E; ++I)
  213. if (*I == V)
  214. return I;
  215. return Vector.end();
  216. }
  217. };
  218. /// If this set is of pointer values, transparently switch over to using
  219. /// SmallPtrSet for performance.
  220. template <typename PointeeType, unsigned N>
  221. class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
  222. /// Equality comparison for SmallSet.
  223. ///
  224. /// Iterates over elements of LHS confirming that each element is also a member
  225. /// of RHS, and that RHS contains no additional values.
  226. /// Equivalent to N calls to RHS.count.
  227. /// For small-set mode amortized complexity is O(N^2)
  228. /// For large-set mode amortized complexity is linear, worst case is O(N^2) (if
  229. /// every hash collides).
  230. template <typename T, unsigned LN, unsigned RN, typename C>
  231. bool operator==(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
  232. if (LHS.size() != RHS.size())
  233. return false;
  234. // All elements in LHS must also be in RHS
  235. return all_of(LHS, [&RHS](const T &E) { return RHS.count(E); });
  236. }
  237. /// Inequality comparison for SmallSet.
  238. ///
  239. /// Equivalent to !(LHS == RHS). See operator== for performance notes.
  240. template <typename T, unsigned LN, unsigned RN, typename C>
  241. bool operator!=(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
  242. return !(LHS == RHS);
  243. }
  244. } // end namespace llvm
  245. #endif // LLVM_ADT_SMALLSET_H
  246. #ifdef __GNUC__
  247. #pragma GCC diagnostic pop
  248. #endif