SmallPtrSet.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- 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. // This file defines the SmallPtrSet class. See the doxygen comment for
  15. // SmallPtrSetImplBase for more details on the algorithm used.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_ADT_SMALLPTRSET_H
  19. #define LLVM_ADT_SMALLPTRSET_H
  20. #include "llvm/ADT/EpochTracker.h"
  21. #include "llvm/Support/Compiler.h"
  22. #include "llvm/Support/ReverseIteration.h"
  23. #include "llvm/Support/type_traits.h"
  24. #include <cassert>
  25. #include <cstddef>
  26. #include <cstdlib>
  27. #include <cstring>
  28. #include <initializer_list>
  29. #include <iterator>
  30. #include <utility>
  31. namespace llvm {
  32. /// SmallPtrSetImplBase - This is the common code shared among all the
  33. /// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
  34. /// for small and one for large sets.
  35. ///
  36. /// Small sets use an array of pointers allocated in the SmallPtrSet object,
  37. /// which is treated as a simple array of pointers. When a pointer is added to
  38. /// the set, the array is scanned to see if the element already exists, if not
  39. /// the element is 'pushed back' onto the array. If we run out of space in the
  40. /// array, we grow into the 'large set' case. SmallSet should be used when the
  41. /// sets are often small. In this case, no memory allocation is used, and only
  42. /// light-weight and cache-efficient scanning is used.
  43. ///
  44. /// Large sets use a classic exponentially-probed hash table. Empty buckets are
  45. /// represented with an illegal pointer value (-1) to allow null pointers to be
  46. /// inserted. Tombstones are represented with another illegal pointer value
  47. /// (-2), to allow deletion. The hash table is resized when the table is 3/4 or
  48. /// more. When this happens, the table is doubled in size.
  49. ///
  50. class SmallPtrSetImplBase : public DebugEpochBase {
  51. friend class SmallPtrSetIteratorImpl;
  52. protected:
  53. /// SmallArray - Points to a fixed size set of buckets, used in 'small mode'.
  54. const void **SmallArray;
  55. /// CurArray - This is the current set of buckets. If equal to SmallArray,
  56. /// then the set is in 'small mode'.
  57. const void **CurArray;
  58. /// CurArraySize - The allocated size of CurArray, always a power of two.
  59. unsigned CurArraySize;
  60. /// Number of elements in CurArray that contain a value or are a tombstone.
  61. /// If small, all these elements are at the beginning of CurArray and the rest
  62. /// is uninitialized.
  63. unsigned NumNonEmpty;
  64. /// Number of tombstones in CurArray.
  65. unsigned NumTombstones;
  66. // Helpers to copy and move construct a SmallPtrSet.
  67. SmallPtrSetImplBase(const void **SmallStorage,
  68. const SmallPtrSetImplBase &that);
  69. SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
  70. SmallPtrSetImplBase &&that);
  71. explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize)
  72. : SmallArray(SmallStorage), CurArray(SmallStorage),
  73. CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) {
  74. assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
  75. "Initial size must be a power of two!");
  76. }
  77. ~SmallPtrSetImplBase() {
  78. if (!isSmall())
  79. free(CurArray);
  80. }
  81. public:
  82. using size_type = unsigned;
  83. SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
  84. LLVM_NODISCARD bool empty() const { return size() == 0; }
  85. size_type size() const { return NumNonEmpty - NumTombstones; }
  86. void clear() {
  87. incrementEpoch();
  88. // If the capacity of the array is huge, and the # elements used is small,
  89. // shrink the array.
  90. if (!isSmall()) {
  91. if (size() * 4 < CurArraySize && CurArraySize > 32)
  92. return shrink_and_clear();
  93. // Fill the array with empty markers.
  94. memset(CurArray, -1, CurArraySize * sizeof(void *));
  95. }
  96. NumNonEmpty = 0;
  97. NumTombstones = 0;
  98. }
  99. protected:
  100. static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); }
  101. static void *getEmptyMarker() {
  102. // Note that -1 is chosen to make clear() efficiently implementable with
  103. // memset and because it's not a valid pointer value.
  104. return reinterpret_cast<void*>(-1);
  105. }
  106. const void **EndPointer() const {
  107. return isSmall() ? CurArray + NumNonEmpty : CurArray + CurArraySize;
  108. }
  109. /// insert_imp - This returns true if the pointer was new to the set, false if
  110. /// it was already in the set. This is hidden from the client so that the
  111. /// derived class can check that the right type of pointer is passed in.
  112. std::pair<const void *const *, bool> insert_imp(const void *Ptr) {
  113. if (isSmall()) {
  114. // Check to see if it is already in the set.
  115. const void **LastTombstone = nullptr;
  116. for (const void **APtr = SmallArray, **E = SmallArray + NumNonEmpty;
  117. APtr != E; ++APtr) {
  118. const void *Value = *APtr;
  119. if (Value == Ptr)
  120. return std::make_pair(APtr, false);
  121. if (Value == getTombstoneMarker())
  122. LastTombstone = APtr;
  123. }
  124. // Did we find any tombstone marker?
  125. if (LastTombstone != nullptr) {
  126. *LastTombstone = Ptr;
  127. --NumTombstones;
  128. incrementEpoch();
  129. return std::make_pair(LastTombstone, true);
  130. }
  131. // Nope, there isn't. If we stay small, just 'pushback' now.
  132. if (NumNonEmpty < CurArraySize) {
  133. SmallArray[NumNonEmpty++] = Ptr;
  134. incrementEpoch();
  135. return std::make_pair(SmallArray + (NumNonEmpty - 1), true);
  136. }
  137. // Otherwise, hit the big set case, which will call grow.
  138. }
  139. return insert_imp_big(Ptr);
  140. }
  141. /// erase_imp - If the set contains the specified pointer, remove it and
  142. /// return true, otherwise return false. This is hidden from the client so
  143. /// that the derived class can check that the right type of pointer is passed
  144. /// in.
  145. bool erase_imp(const void * Ptr) {
  146. const void *const *P = find_imp(Ptr);
  147. if (P == EndPointer())
  148. return false;
  149. const void **Loc = const_cast<const void **>(P);
  150. assert(*Loc == Ptr && "broken find!");
  151. *Loc = getTombstoneMarker();
  152. NumTombstones++;
  153. return true;
  154. }
  155. /// Returns the raw pointer needed to construct an iterator. If element not
  156. /// found, this will be EndPointer. Otherwise, it will be a pointer to the
  157. /// slot which stores Ptr;
  158. const void *const * find_imp(const void * Ptr) const {
  159. if (isSmall()) {
  160. // Linear search for the item.
  161. for (const void *const *APtr = SmallArray,
  162. *const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr)
  163. if (*APtr == Ptr)
  164. return APtr;
  165. return EndPointer();
  166. }
  167. // Big set case.
  168. auto *Bucket = FindBucketFor(Ptr);
  169. if (*Bucket == Ptr)
  170. return Bucket;
  171. return EndPointer();
  172. }
  173. private:
  174. bool isSmall() const { return CurArray == SmallArray; }
  175. std::pair<const void *const *, bool> insert_imp_big(const void *Ptr);
  176. const void * const *FindBucketFor(const void *Ptr) const;
  177. void shrink_and_clear();
  178. /// Grow - Allocate a larger backing store for the buckets and move it over.
  179. void Grow(unsigned NewSize);
  180. protected:
  181. /// swap - Swaps the elements of two sets.
  182. /// Note: This method assumes that both sets have the same small size.
  183. void swap(SmallPtrSetImplBase &RHS);
  184. void CopyFrom(const SmallPtrSetImplBase &RHS);
  185. void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
  186. private:
  187. /// Code shared by MoveFrom() and move constructor.
  188. void MoveHelper(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
  189. /// Code shared by CopyFrom() and copy constructor.
  190. void CopyHelper(const SmallPtrSetImplBase &RHS);
  191. };
  192. /// SmallPtrSetIteratorImpl - This is the common base class shared between all
  193. /// instances of SmallPtrSetIterator.
  194. class SmallPtrSetIteratorImpl {
  195. protected:
  196. const void *const *Bucket;
  197. const void *const *End;
  198. public:
  199. explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
  200. : Bucket(BP), End(E) {
  201. if (shouldReverseIterate()) {
  202. RetreatIfNotValid();
  203. return;
  204. }
  205. AdvanceIfNotValid();
  206. }
  207. bool operator==(const SmallPtrSetIteratorImpl &RHS) const {
  208. return Bucket == RHS.Bucket;
  209. }
  210. bool operator!=(const SmallPtrSetIteratorImpl &RHS) const {
  211. return Bucket != RHS.Bucket;
  212. }
  213. protected:
  214. /// AdvanceIfNotValid - If the current bucket isn't valid, advance to a bucket
  215. /// that is. This is guaranteed to stop because the end() bucket is marked
  216. /// valid.
  217. void AdvanceIfNotValid() {
  218. assert(Bucket <= End);
  219. while (Bucket != End &&
  220. (*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
  221. *Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
  222. ++Bucket;
  223. }
  224. void RetreatIfNotValid() {
  225. assert(Bucket >= End);
  226. while (Bucket != End &&
  227. (Bucket[-1] == SmallPtrSetImplBase::getEmptyMarker() ||
  228. Bucket[-1] == SmallPtrSetImplBase::getTombstoneMarker())) {
  229. --Bucket;
  230. }
  231. }
  232. };
  233. /// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
  234. template <typename PtrTy>
  235. class SmallPtrSetIterator : public SmallPtrSetIteratorImpl,
  236. DebugEpochBase::HandleBase {
  237. using PtrTraits = PointerLikeTypeTraits<PtrTy>;
  238. public:
  239. using value_type = PtrTy;
  240. using reference = PtrTy;
  241. using pointer = PtrTy;
  242. using difference_type = std::ptrdiff_t;
  243. using iterator_category = std::forward_iterator_tag;
  244. explicit SmallPtrSetIterator(const void *const *BP, const void *const *E,
  245. const DebugEpochBase &Epoch)
  246. : SmallPtrSetIteratorImpl(BP, E), DebugEpochBase::HandleBase(&Epoch) {}
  247. // Most methods are provided by the base class.
  248. const PtrTy operator*() const {
  249. assert(isHandleInSync() && "invalid iterator access!");
  250. if (shouldReverseIterate()) {
  251. assert(Bucket > End);
  252. return PtrTraits::getFromVoidPointer(const_cast<void *>(Bucket[-1]));
  253. }
  254. assert(Bucket < End);
  255. return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket));
  256. }
  257. inline SmallPtrSetIterator& operator++() { // Preincrement
  258. assert(isHandleInSync() && "invalid iterator access!");
  259. if (shouldReverseIterate()) {
  260. --Bucket;
  261. RetreatIfNotValid();
  262. return *this;
  263. }
  264. ++Bucket;
  265. AdvanceIfNotValid();
  266. return *this;
  267. }
  268. SmallPtrSetIterator operator++(int) { // Postincrement
  269. SmallPtrSetIterator tmp = *this;
  270. ++*this;
  271. return tmp;
  272. }
  273. };
  274. /// RoundUpToPowerOfTwo - This is a helper template that rounds N up to the next
  275. /// power of two (which means N itself if N is already a power of two).
  276. template<unsigned N>
  277. struct RoundUpToPowerOfTwo;
  278. /// RoundUpToPowerOfTwoH - If N is not a power of two, increase it. This is a
  279. /// helper template used to implement RoundUpToPowerOfTwo.
  280. template<unsigned N, bool isPowerTwo>
  281. struct RoundUpToPowerOfTwoH {
  282. enum { Val = N };
  283. };
  284. template<unsigned N>
  285. struct RoundUpToPowerOfTwoH<N, false> {
  286. enum {
  287. // We could just use NextVal = N+1, but this converges faster. N|(N-1) sets
  288. // the right-most zero bits to one all at once, e.g. 0b0011000 -> 0b0011111.
  289. Val = RoundUpToPowerOfTwo<(N|(N-1)) + 1>::Val
  290. };
  291. };
  292. template<unsigned N>
  293. struct RoundUpToPowerOfTwo {
  294. enum { Val = RoundUpToPowerOfTwoH<N, (N&(N-1)) == 0>::Val };
  295. };
  296. /// A templated base class for \c SmallPtrSet which provides the
  297. /// typesafe interface that is common across all small sizes.
  298. ///
  299. /// This is particularly useful for passing around between interface boundaries
  300. /// to avoid encoding a particular small size in the interface boundary.
  301. template <typename PtrType>
  302. class SmallPtrSetImpl : public SmallPtrSetImplBase {
  303. using ConstPtrType = typename add_const_past_pointer<PtrType>::type;
  304. using PtrTraits = PointerLikeTypeTraits<PtrType>;
  305. using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
  306. protected:
  307. // Forward constructors to the base.
  308. using SmallPtrSetImplBase::SmallPtrSetImplBase;
  309. public:
  310. using iterator = SmallPtrSetIterator<PtrType>;
  311. using const_iterator = SmallPtrSetIterator<PtrType>;
  312. using key_type = ConstPtrType;
  313. using value_type = PtrType;
  314. SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
  315. /// Inserts Ptr if and only if there is no element in the container equal to
  316. /// Ptr. The bool component of the returned pair is true if and only if the
  317. /// insertion takes place, and the iterator component of the pair points to
  318. /// the element equal to Ptr.
  319. std::pair<iterator, bool> insert(PtrType Ptr) {
  320. auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr));
  321. return std::make_pair(makeIterator(p.first), p.second);
  322. }
  323. /// erase - If the set contains the specified pointer, remove it and return
  324. /// true, otherwise return false.
  325. bool erase(PtrType Ptr) {
  326. return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
  327. }
  328. /// count - Return 1 if the specified pointer is in the set, 0 otherwise.
  329. size_type count(ConstPtrType Ptr) const {
  330. return find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)) != EndPointer();
  331. }
  332. iterator find(ConstPtrType Ptr) const {
  333. return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)));
  334. }
  335. bool contains(ConstPtrType Ptr) const {
  336. return find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)) != EndPointer();
  337. }
  338. template <typename IterT>
  339. void insert(IterT I, IterT E) {
  340. for (; I != E; ++I)
  341. insert(*I);
  342. }
  343. void insert(std::initializer_list<PtrType> IL) {
  344. insert(IL.begin(), IL.end());
  345. }
  346. iterator begin() const {
  347. if (shouldReverseIterate())
  348. return makeIterator(EndPointer() - 1);
  349. return makeIterator(CurArray);
  350. }
  351. iterator end() const { return makeIterator(EndPointer()); }
  352. private:
  353. /// Create an iterator that dereferences to same place as the given pointer.
  354. iterator makeIterator(const void *const *P) const {
  355. if (shouldReverseIterate())
  356. return iterator(P == EndPointer() ? CurArray : P + 1, CurArray, *this);
  357. return iterator(P, EndPointer(), *this);
  358. }
  359. };
  360. /// Equality comparison for SmallPtrSet.
  361. ///
  362. /// Iterates over elements of LHS confirming that each value from LHS is also in
  363. /// RHS, and that no additional values are in RHS.
  364. template <typename PtrType>
  365. bool operator==(const SmallPtrSetImpl<PtrType> &LHS,
  366. const SmallPtrSetImpl<PtrType> &RHS) {
  367. if (LHS.size() != RHS.size())
  368. return false;
  369. for (const auto *KV : LHS)
  370. if (!RHS.count(KV))
  371. return false;
  372. return true;
  373. }
  374. /// Inequality comparison for SmallPtrSet.
  375. ///
  376. /// Equivalent to !(LHS == RHS).
  377. template <typename PtrType>
  378. bool operator!=(const SmallPtrSetImpl<PtrType> &LHS,
  379. const SmallPtrSetImpl<PtrType> &RHS) {
  380. return !(LHS == RHS);
  381. }
  382. /// SmallPtrSet - This class implements a set which is optimized for holding
  383. /// SmallSize or less elements. This internally rounds up SmallSize to the next
  384. /// power of two if it is not already a power of two. See the comments above
  385. /// SmallPtrSetImplBase for details of the algorithm.
  386. template<class PtrType, unsigned SmallSize>
  387. class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
  388. // In small mode SmallPtrSet uses linear search for the elements, so it is
  389. // not a good idea to choose this value too high. You may consider using a
  390. // DenseSet<> instead if you expect many elements in the set.
  391. static_assert(SmallSize <= 32, "SmallSize should be small");
  392. using BaseT = SmallPtrSetImpl<PtrType>;
  393. // Make sure that SmallSize is a power of two, round up if not.
  394. enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
  395. /// SmallStorage - Fixed size storage used in 'small mode'.
  396. const void *SmallStorage[SmallSizePowTwo];
  397. public:
  398. SmallPtrSet() : BaseT(SmallStorage, SmallSizePowTwo) {}
  399. SmallPtrSet(const SmallPtrSet &that) : BaseT(SmallStorage, that) {}
  400. SmallPtrSet(SmallPtrSet &&that)
  401. : BaseT(SmallStorage, SmallSizePowTwo, std::move(that)) {}
  402. template<typename It>
  403. SmallPtrSet(It I, It E) : BaseT(SmallStorage, SmallSizePowTwo) {
  404. this->insert(I, E);
  405. }
  406. SmallPtrSet(std::initializer_list<PtrType> IL)
  407. : BaseT(SmallStorage, SmallSizePowTwo) {
  408. this->insert(IL.begin(), IL.end());
  409. }
  410. SmallPtrSet<PtrType, SmallSize> &
  411. operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
  412. if (&RHS != this)
  413. this->CopyFrom(RHS);
  414. return *this;
  415. }
  416. SmallPtrSet<PtrType, SmallSize> &
  417. operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
  418. if (&RHS != this)
  419. this->MoveFrom(SmallSizePowTwo, std::move(RHS));
  420. return *this;
  421. }
  422. SmallPtrSet<PtrType, SmallSize> &
  423. operator=(std::initializer_list<PtrType> IL) {
  424. this->clear();
  425. this->insert(IL.begin(), IL.end());
  426. return *this;
  427. }
  428. /// swap - Swaps the elements of two sets.
  429. void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
  430. SmallPtrSetImplBase::swap(RHS);
  431. }
  432. };
  433. } // end namespace llvm
  434. namespace std {
  435. /// Implement std::swap in terms of SmallPtrSet swap.
  436. template<class T, unsigned N>
  437. inline void swap(llvm::SmallPtrSet<T, N> &LHS, llvm::SmallPtrSet<T, N> &RHS) {
  438. LHS.swap(RHS);
  439. }
  440. } // end namespace std
  441. #endif // LLVM_ADT_SMALLPTRSET_H
  442. #ifdef __GNUC__
  443. #pragma GCC diagnostic pop
  444. #endif