SmallPtrSet.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. //===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
  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. // This file implements the SmallPtrSet class. See SmallPtrSet.h for an
  10. // overview of the algorithm.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/ADT/SmallPtrSet.h"
  14. #include "llvm/ADT/DenseMapInfo.h"
  15. #include "llvm/Support/MathExtras.h"
  16. #include "llvm/Support/MemAlloc.h"
  17. #include <algorithm>
  18. #include <cassert>
  19. #include <cstdlib>
  20. using namespace llvm;
  21. void SmallPtrSetImplBase::shrink_and_clear() {
  22. assert(!isSmall() && "Can't shrink a small set!");
  23. free(CurArray);
  24. // Reduce the number of buckets.
  25. unsigned Size = size();
  26. CurArraySize = Size > 16 ? 1 << (Log2_32_Ceil(Size) + 1) : 32;
  27. NumNonEmpty = NumTombstones = 0;
  28. // Install the new array. Clear all the buckets to empty.
  29. CurArray = (const void**)safe_malloc(sizeof(void*) * CurArraySize);
  30. memset(CurArray, -1, CurArraySize*sizeof(void*));
  31. }
  32. std::pair<const void *const *, bool>
  33. SmallPtrSetImplBase::insert_imp_big(const void *Ptr) {
  34. if (LLVM_UNLIKELY(size() * 4 >= CurArraySize * 3)) {
  35. // If more than 3/4 of the array is full, grow.
  36. Grow(CurArraySize < 64 ? 128 : CurArraySize * 2);
  37. } else if (LLVM_UNLIKELY(CurArraySize - NumNonEmpty < CurArraySize / 8)) {
  38. // If fewer of 1/8 of the array is empty (meaning that many are filled with
  39. // tombstones), rehash.
  40. Grow(CurArraySize);
  41. }
  42. // Okay, we know we have space. Find a hash bucket.
  43. const void **Bucket = const_cast<const void**>(FindBucketFor(Ptr));
  44. if (*Bucket == Ptr)
  45. return std::make_pair(Bucket, false); // Already inserted, good.
  46. // Otherwise, insert it!
  47. if (*Bucket == getTombstoneMarker())
  48. --NumTombstones;
  49. else
  50. ++NumNonEmpty; // Track density.
  51. *Bucket = Ptr;
  52. incrementEpoch();
  53. return std::make_pair(Bucket, true);
  54. }
  55. const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const {
  56. unsigned Bucket = DenseMapInfo<void *>::getHashValue(Ptr) & (CurArraySize-1);
  57. unsigned ArraySize = CurArraySize;
  58. unsigned ProbeAmt = 1;
  59. const void *const *Array = CurArray;
  60. const void *const *Tombstone = nullptr;
  61. while (true) {
  62. // If we found an empty bucket, the pointer doesn't exist in the set.
  63. // Return a tombstone if we've seen one so far, or the empty bucket if
  64. // not.
  65. if (LLVM_LIKELY(Array[Bucket] == getEmptyMarker()))
  66. return Tombstone ? Tombstone : Array+Bucket;
  67. // Found Ptr's bucket?
  68. if (LLVM_LIKELY(Array[Bucket] == Ptr))
  69. return Array+Bucket;
  70. // If this is a tombstone, remember it. If Ptr ends up not in the set, we
  71. // prefer to return it than something that would require more probing.
  72. if (Array[Bucket] == getTombstoneMarker() && !Tombstone)
  73. Tombstone = Array+Bucket; // Remember the first tombstone found.
  74. // It's a hash collision or a tombstone. Reprobe.
  75. Bucket = (Bucket + ProbeAmt++) & (ArraySize-1);
  76. }
  77. }
  78. /// Grow - Allocate a larger backing store for the buckets and move it over.
  79. ///
  80. void SmallPtrSetImplBase::Grow(unsigned NewSize) {
  81. const void **OldBuckets = CurArray;
  82. const void **OldEnd = EndPointer();
  83. bool WasSmall = isSmall();
  84. // Install the new array. Clear all the buckets to empty.
  85. const void **NewBuckets = (const void**) safe_malloc(sizeof(void*) * NewSize);
  86. // Reset member only if memory was allocated successfully
  87. CurArray = NewBuckets;
  88. CurArraySize = NewSize;
  89. memset(CurArray, -1, NewSize*sizeof(void*));
  90. // Copy over all valid entries.
  91. for (const void **BucketPtr = OldBuckets; BucketPtr != OldEnd; ++BucketPtr) {
  92. // Copy over the element if it is valid.
  93. const void *Elt = *BucketPtr;
  94. if (Elt != getTombstoneMarker() && Elt != getEmptyMarker())
  95. *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt);
  96. }
  97. if (!WasSmall)
  98. free(OldBuckets);
  99. NumNonEmpty -= NumTombstones;
  100. NumTombstones = 0;
  101. }
  102. SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
  103. const SmallPtrSetImplBase &that) {
  104. SmallArray = SmallStorage;
  105. // If we're becoming small, prepare to insert into our stack space
  106. if (that.isSmall()) {
  107. CurArray = SmallArray;
  108. // Otherwise, allocate new heap space (unless we were the same size)
  109. } else {
  110. CurArray = (const void**)safe_malloc(sizeof(void*) * that.CurArraySize);
  111. }
  112. // Copy over the that array.
  113. CopyHelper(that);
  114. }
  115. SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
  116. unsigned SmallSize,
  117. SmallPtrSetImplBase &&that) {
  118. SmallArray = SmallStorage;
  119. MoveHelper(SmallSize, std::move(that));
  120. }
  121. void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) {
  122. assert(&RHS != this && "Self-copy should be handled by the caller.");
  123. if (isSmall() && RHS.isSmall())
  124. assert(CurArraySize == RHS.CurArraySize &&
  125. "Cannot assign sets with different small sizes");
  126. // If we're becoming small, prepare to insert into our stack space
  127. if (RHS.isSmall()) {
  128. if (!isSmall())
  129. free(CurArray);
  130. CurArray = SmallArray;
  131. // Otherwise, allocate new heap space (unless we were the same size)
  132. } else if (CurArraySize != RHS.CurArraySize) {
  133. if (isSmall())
  134. CurArray = (const void**)safe_malloc(sizeof(void*) * RHS.CurArraySize);
  135. else {
  136. const void **T = (const void**)safe_realloc(CurArray,
  137. sizeof(void*) * RHS.CurArraySize);
  138. CurArray = T;
  139. }
  140. }
  141. CopyHelper(RHS);
  142. }
  143. void SmallPtrSetImplBase::CopyHelper(const SmallPtrSetImplBase &RHS) {
  144. // Copy over the new array size
  145. CurArraySize = RHS.CurArraySize;
  146. // Copy over the contents from the other set
  147. std::copy(RHS.CurArray, RHS.EndPointer(), CurArray);
  148. NumNonEmpty = RHS.NumNonEmpty;
  149. NumTombstones = RHS.NumTombstones;
  150. }
  151. void SmallPtrSetImplBase::MoveFrom(unsigned SmallSize,
  152. SmallPtrSetImplBase &&RHS) {
  153. if (!isSmall())
  154. free(CurArray);
  155. MoveHelper(SmallSize, std::move(RHS));
  156. }
  157. void SmallPtrSetImplBase::MoveHelper(unsigned SmallSize,
  158. SmallPtrSetImplBase &&RHS) {
  159. assert(&RHS != this && "Self-move should be handled by the caller.");
  160. if (RHS.isSmall()) {
  161. // Copy a small RHS rather than moving.
  162. CurArray = SmallArray;
  163. std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, CurArray);
  164. } else {
  165. CurArray = RHS.CurArray;
  166. RHS.CurArray = RHS.SmallArray;
  167. }
  168. // Copy the rest of the trivial members.
  169. CurArraySize = RHS.CurArraySize;
  170. NumNonEmpty = RHS.NumNonEmpty;
  171. NumTombstones = RHS.NumTombstones;
  172. // Make the RHS small and empty.
  173. RHS.CurArraySize = SmallSize;
  174. assert(RHS.CurArray == RHS.SmallArray);
  175. RHS.NumNonEmpty = 0;
  176. RHS.NumTombstones = 0;
  177. }
  178. void SmallPtrSetImplBase::swap(SmallPtrSetImplBase &RHS) {
  179. if (this == &RHS) return;
  180. // We can only avoid copying elements if neither set is small.
  181. if (!this->isSmall() && !RHS.isSmall()) {
  182. std::swap(this->CurArray, RHS.CurArray);
  183. std::swap(this->CurArraySize, RHS.CurArraySize);
  184. std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
  185. std::swap(this->NumTombstones, RHS.NumTombstones);
  186. return;
  187. }
  188. // FIXME: From here on we assume that both sets have the same small size.
  189. // If only RHS is small, copy the small elements into LHS and move the pointer
  190. // from LHS to RHS.
  191. if (!this->isSmall() && RHS.isSmall()) {
  192. assert(RHS.CurArray == RHS.SmallArray);
  193. std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, this->SmallArray);
  194. std::swap(RHS.CurArraySize, this->CurArraySize);
  195. std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
  196. std::swap(this->NumTombstones, RHS.NumTombstones);
  197. RHS.CurArray = this->CurArray;
  198. this->CurArray = this->SmallArray;
  199. return;
  200. }
  201. // If only LHS is small, copy the small elements into RHS and move the pointer
  202. // from RHS to LHS.
  203. if (this->isSmall() && !RHS.isSmall()) {
  204. assert(this->CurArray == this->SmallArray);
  205. std::copy(this->CurArray, this->CurArray + this->NumNonEmpty,
  206. RHS.SmallArray);
  207. std::swap(RHS.CurArraySize, this->CurArraySize);
  208. std::swap(RHS.NumNonEmpty, this->NumNonEmpty);
  209. std::swap(RHS.NumTombstones, this->NumTombstones);
  210. this->CurArray = RHS.CurArray;
  211. RHS.CurArray = RHS.SmallArray;
  212. return;
  213. }
  214. // Both a small, just swap the small elements.
  215. assert(this->isSmall() && RHS.isSmall());
  216. unsigned MinNonEmpty = std::min(this->NumNonEmpty, RHS.NumNonEmpty);
  217. std::swap_ranges(this->SmallArray, this->SmallArray + MinNonEmpty,
  218. RHS.SmallArray);
  219. if (this->NumNonEmpty > MinNonEmpty) {
  220. std::copy(this->SmallArray + MinNonEmpty,
  221. this->SmallArray + this->NumNonEmpty,
  222. RHS.SmallArray + MinNonEmpty);
  223. } else {
  224. std::copy(RHS.SmallArray + MinNonEmpty, RHS.SmallArray + RHS.NumNonEmpty,
  225. this->SmallArray + MinNonEmpty);
  226. }
  227. assert(this->CurArraySize == RHS.CurArraySize);
  228. std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
  229. std::swap(this->NumTombstones, RHS.NumTombstones);
  230. }