SmallPtrSet.h 17 KB

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