1f22ef01cSRoman Divacky //===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
2f22ef01cSRoman Divacky //
3f22ef01cSRoman Divacky //                     The LLVM Compiler Infrastructure
4f22ef01cSRoman Divacky //
5f22ef01cSRoman Divacky // This file is distributed under the University of Illinois Open Source
6f22ef01cSRoman Divacky // License. See LICENSE.TXT for details.
7f22ef01cSRoman Divacky //
8f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
9f22ef01cSRoman Divacky //
10f22ef01cSRoman Divacky // This file implements the SmallPtrSet class.  See SmallPtrSet.h for an
11f22ef01cSRoman Divacky // overview of the algorithm.
12f22ef01cSRoman Divacky //
13f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
14f22ef01cSRoman Divacky 
15f22ef01cSRoman Divacky #include "llvm/ADT/SmallPtrSet.h"
16cb4dff85SDimitry Andric #include "llvm/ADT/DenseMapInfo.h"
17f22ef01cSRoman Divacky #include "llvm/Support/MathExtras.h"
182cab237bSDimitry Andric #include "llvm/Support/ErrorHandling.h"
19dff0c46cSDimitry Andric #include <algorithm>
20d88c1a5aSDimitry Andric #include <cassert>
21f22ef01cSRoman Divacky #include <cstdlib>
22f22ef01cSRoman Divacky 
23f22ef01cSRoman Divacky using namespace llvm;
24f22ef01cSRoman Divacky 
shrink_and_clear()2591bc56edSDimitry Andric void SmallPtrSetImplBase::shrink_and_clear() {
26f22ef01cSRoman Divacky   assert(!isSmall() && "Can't shrink a small set!");
27f22ef01cSRoman Divacky   free(CurArray);
28f22ef01cSRoman Divacky 
29f22ef01cSRoman Divacky   // Reduce the number of buckets.
303ca95b02SDimitry Andric   unsigned Size = size();
313ca95b02SDimitry Andric   CurArraySize = Size > 16 ? 1 << (Log2_32_Ceil(Size) + 1) : 32;
323ca95b02SDimitry Andric   NumNonEmpty = NumTombstones = 0;
33f22ef01cSRoman Divacky 
34f22ef01cSRoman Divacky   // Install the new array.  Clear all the buckets to empty.
35*4ba319b5SDimitry Andric   CurArray = (const void**)safe_malloc(sizeof(void*) * CurArraySize);
362cab237bSDimitry Andric 
37f22ef01cSRoman Divacky   memset(CurArray, -1, CurArraySize*sizeof(void*));
38f22ef01cSRoman Divacky }
39f22ef01cSRoman Divacky 
4039d628a0SDimitry Andric std::pair<const void *const *, bool>
insert_imp_big(const void * Ptr)413ca95b02SDimitry Andric SmallPtrSetImplBase::insert_imp_big(const void *Ptr) {
423ca95b02SDimitry Andric   if (LLVM_UNLIKELY(size() * 4 >= CurArraySize * 3)) {
43f22ef01cSRoman Divacky     // If more than 3/4 of the array is full, grow.
443b0f4066SDimitry Andric     Grow(CurArraySize < 64 ? 128 : CurArraySize * 2);
453ca95b02SDimitry Andric   } else if (LLVM_UNLIKELY(CurArraySize - NumNonEmpty < CurArraySize / 8)) {
463b0f4066SDimitry Andric     // If fewer of 1/8 of the array is empty (meaning that many are filled with
473b0f4066SDimitry Andric     // tombstones), rehash.
483b0f4066SDimitry Andric     Grow(CurArraySize);
493b0f4066SDimitry Andric   }
50f22ef01cSRoman Divacky 
51f22ef01cSRoman Divacky   // Okay, we know we have space.  Find a hash bucket.
52f22ef01cSRoman Divacky   const void **Bucket = const_cast<const void**>(FindBucketFor(Ptr));
5339d628a0SDimitry Andric   if (*Bucket == Ptr)
5439d628a0SDimitry Andric     return std::make_pair(Bucket, false); // Already inserted, good.
55f22ef01cSRoman Divacky 
56f22ef01cSRoman Divacky   // Otherwise, insert it!
57f22ef01cSRoman Divacky   if (*Bucket == getTombstoneMarker())
58f22ef01cSRoman Divacky     --NumTombstones;
593ca95b02SDimitry Andric   else
603ca95b02SDimitry Andric     ++NumNonEmpty; // Track density.
61f22ef01cSRoman Divacky   *Bucket = Ptr;
622cab237bSDimitry Andric   incrementEpoch();
6339d628a0SDimitry Andric   return std::make_pair(Bucket, true);
64f22ef01cSRoman Divacky }
65f22ef01cSRoman Divacky 
FindBucketFor(const void * Ptr) const6691bc56edSDimitry Andric const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const {
67cb4dff85SDimitry Andric   unsigned Bucket = DenseMapInfo<void *>::getHashValue(Ptr) & (CurArraySize-1);
68f22ef01cSRoman Divacky   unsigned ArraySize = CurArraySize;
69f22ef01cSRoman Divacky   unsigned ProbeAmt = 1;
70f22ef01cSRoman Divacky   const void *const *Array = CurArray;
7191bc56edSDimitry Andric   const void *const *Tombstone = nullptr;
72d88c1a5aSDimitry Andric   while (true) {
73f22ef01cSRoman Divacky     // If we found an empty bucket, the pointer doesn't exist in the set.
74f22ef01cSRoman Divacky     // Return a tombstone if we've seen one so far, or the empty bucket if
75f22ef01cSRoman Divacky     // not.
76ff0cc061SDimitry Andric     if (LLVM_LIKELY(Array[Bucket] == getEmptyMarker()))
77f22ef01cSRoman Divacky       return Tombstone ? Tombstone : Array+Bucket;
78f22ef01cSRoman Divacky 
79ff0cc061SDimitry Andric     // Found Ptr's bucket?
80ff0cc061SDimitry Andric     if (LLVM_LIKELY(Array[Bucket] == Ptr))
81ff0cc061SDimitry Andric       return Array+Bucket;
82ff0cc061SDimitry Andric 
83f22ef01cSRoman Divacky     // If this is a tombstone, remember it.  If Ptr ends up not in the set, we
84f22ef01cSRoman Divacky     // prefer to return it than something that would require more probing.
85f22ef01cSRoman Divacky     if (Array[Bucket] == getTombstoneMarker() && !Tombstone)
86f22ef01cSRoman Divacky       Tombstone = Array+Bucket;  // Remember the first tombstone found.
87f22ef01cSRoman Divacky 
88f22ef01cSRoman Divacky     // It's a hash collision or a tombstone. Reprobe.
89f22ef01cSRoman Divacky     Bucket = (Bucket + ProbeAmt++) & (ArraySize-1);
90f22ef01cSRoman Divacky   }
91f22ef01cSRoman Divacky }
92f22ef01cSRoman Divacky 
93f22ef01cSRoman Divacky /// Grow - Allocate a larger backing store for the buckets and move it over.
94f22ef01cSRoman Divacky ///
Grow(unsigned NewSize)9591bc56edSDimitry Andric void SmallPtrSetImplBase::Grow(unsigned NewSize) {
96f22ef01cSRoman Divacky   const void **OldBuckets = CurArray;
973ca95b02SDimitry Andric   const void **OldEnd = EndPointer();
98f22ef01cSRoman Divacky   bool WasSmall = isSmall();
99f22ef01cSRoman Divacky 
100f22ef01cSRoman Divacky   // Install the new array.  Clear all the buckets to empty.
101*4ba319b5SDimitry Andric   const void **NewBuckets = (const void**) safe_malloc(sizeof(void*) * NewSize);
1022cab237bSDimitry Andric 
1032cab237bSDimitry Andric   // Reset member only if memory was allocated successfully
1042cab237bSDimitry Andric   CurArray = NewBuckets;
105f22ef01cSRoman Divacky   CurArraySize = NewSize;
106f22ef01cSRoman Divacky   memset(CurArray, -1, NewSize*sizeof(void*));
107f22ef01cSRoman Divacky 
108f22ef01cSRoman Divacky   // Copy over all valid entries.
1093ca95b02SDimitry Andric   for (const void **BucketPtr = OldBuckets; BucketPtr != OldEnd; ++BucketPtr) {
110f22ef01cSRoman Divacky     // Copy over the element if it is valid.
111f22ef01cSRoman Divacky     const void *Elt = *BucketPtr;
112f22ef01cSRoman Divacky     if (Elt != getTombstoneMarker() && Elt != getEmptyMarker())
113f22ef01cSRoman Divacky       *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt);
114f22ef01cSRoman Divacky   }
115f22ef01cSRoman Divacky 
1163ca95b02SDimitry Andric   if (!WasSmall)
117f22ef01cSRoman Divacky     free(OldBuckets);
1183ca95b02SDimitry Andric   NumNonEmpty -= NumTombstones;
119f22ef01cSRoman Divacky   NumTombstones = 0;
120f22ef01cSRoman Divacky }
121f22ef01cSRoman Divacky 
SmallPtrSetImplBase(const void ** SmallStorage,const SmallPtrSetImplBase & that)12291bc56edSDimitry Andric SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
12391bc56edSDimitry Andric                                          const SmallPtrSetImplBase &that) {
124ffd1746dSEd Schouten   SmallArray = SmallStorage;
125ffd1746dSEd Schouten 
126f22ef01cSRoman Divacky   // If we're becoming small, prepare to insert into our stack space
127f22ef01cSRoman Divacky   if (that.isSmall()) {
128ffd1746dSEd Schouten     CurArray = SmallArray;
129f22ef01cSRoman Divacky   // Otherwise, allocate new heap space (unless we were the same size)
130f22ef01cSRoman Divacky   } else {
131*4ba319b5SDimitry Andric     CurArray = (const void**)safe_malloc(sizeof(void*) * that.CurArraySize);
132f22ef01cSRoman Divacky   }
133f22ef01cSRoman Divacky 
1343ca95b02SDimitry Andric   // Copy over the that array.
1353ca95b02SDimitry Andric   CopyHelper(that);
136f22ef01cSRoman Divacky }
137f22ef01cSRoman Divacky 
SmallPtrSetImplBase(const void ** SmallStorage,unsigned SmallSize,SmallPtrSetImplBase && that)13891bc56edSDimitry Andric SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
13991bc56edSDimitry Andric                                          unsigned SmallSize,
14091bc56edSDimitry Andric                                          SmallPtrSetImplBase &&that) {
14191bc56edSDimitry Andric   SmallArray = SmallStorage;
1423ca95b02SDimitry Andric   MoveHelper(SmallSize, std::move(that));
14339d628a0SDimitry Andric }
14491bc56edSDimitry Andric 
CopyFrom(const SmallPtrSetImplBase & RHS)14591bc56edSDimitry Andric void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) {
14691bc56edSDimitry Andric   assert(&RHS != this && "Self-copy should be handled by the caller.");
14791bc56edSDimitry Andric 
148f22ef01cSRoman Divacky   if (isSmall() && RHS.isSmall())
149f22ef01cSRoman Divacky     assert(CurArraySize == RHS.CurArraySize &&
150f22ef01cSRoman Divacky            "Cannot assign sets with different small sizes");
151f22ef01cSRoman Divacky 
152f22ef01cSRoman Divacky   // If we're becoming small, prepare to insert into our stack space
153f22ef01cSRoman Divacky   if (RHS.isSmall()) {
154f22ef01cSRoman Divacky     if (!isSmall())
155f22ef01cSRoman Divacky       free(CurArray);
156ffd1746dSEd Schouten     CurArray = SmallArray;
157f22ef01cSRoman Divacky   // Otherwise, allocate new heap space (unless we were the same size)
158f22ef01cSRoman Divacky   } else if (CurArraySize != RHS.CurArraySize) {
159f22ef01cSRoman Divacky     if (isSmall())
160*4ba319b5SDimitry Andric       CurArray = (const void**)safe_malloc(sizeof(void*) * RHS.CurArraySize);
161f785676fSDimitry Andric     else {
162*4ba319b5SDimitry Andric       const void **T = (const void**)safe_realloc(CurArray,
163f785676fSDimitry Andric                                              sizeof(void*) * RHS.CurArraySize);
164f785676fSDimitry Andric       CurArray = T;
165f785676fSDimitry Andric     }
166f22ef01cSRoman Divacky   }
167f22ef01cSRoman Divacky 
1683ca95b02SDimitry Andric   CopyHelper(RHS);
1693ca95b02SDimitry Andric }
1703ca95b02SDimitry Andric 
CopyHelper(const SmallPtrSetImplBase & RHS)1713ca95b02SDimitry Andric void SmallPtrSetImplBase::CopyHelper(const SmallPtrSetImplBase &RHS) {
172f22ef01cSRoman Divacky   // Copy over the new array size
173f22ef01cSRoman Divacky   CurArraySize = RHS.CurArraySize;
174f22ef01cSRoman Divacky 
175f22ef01cSRoman Divacky   // Copy over the contents from the other set
1763ca95b02SDimitry Andric   std::copy(RHS.CurArray, RHS.EndPointer(), CurArray);
177f22ef01cSRoman Divacky 
1783ca95b02SDimitry Andric   NumNonEmpty = RHS.NumNonEmpty;
179f22ef01cSRoman Divacky   NumTombstones = RHS.NumTombstones;
180f22ef01cSRoman Divacky }
181f22ef01cSRoman Divacky 
MoveFrom(unsigned SmallSize,SmallPtrSetImplBase && RHS)18291bc56edSDimitry Andric void SmallPtrSetImplBase::MoveFrom(unsigned SmallSize,
18391bc56edSDimitry Andric                                    SmallPtrSetImplBase &&RHS) {
18491bc56edSDimitry Andric   if (!isSmall())
18591bc56edSDimitry Andric     free(CurArray);
1863ca95b02SDimitry Andric   MoveHelper(SmallSize, std::move(RHS));
1873ca95b02SDimitry Andric }
1883ca95b02SDimitry Andric 
MoveHelper(unsigned SmallSize,SmallPtrSetImplBase && RHS)1893ca95b02SDimitry Andric void SmallPtrSetImplBase::MoveHelper(unsigned SmallSize,
1903ca95b02SDimitry Andric                                      SmallPtrSetImplBase &&RHS) {
1913ca95b02SDimitry Andric   assert(&RHS != this && "Self-move should be handled by the caller.");
19291bc56edSDimitry Andric 
19391bc56edSDimitry Andric   if (RHS.isSmall()) {
19491bc56edSDimitry Andric     // Copy a small RHS rather than moving.
19591bc56edSDimitry Andric     CurArray = SmallArray;
1963ca95b02SDimitry Andric     std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, CurArray);
19791bc56edSDimitry Andric   } else {
19891bc56edSDimitry Andric     CurArray = RHS.CurArray;
19991bc56edSDimitry Andric     RHS.CurArray = RHS.SmallArray;
20091bc56edSDimitry Andric   }
20191bc56edSDimitry Andric 
20291bc56edSDimitry Andric   // Copy the rest of the trivial members.
20391bc56edSDimitry Andric   CurArraySize = RHS.CurArraySize;
2043ca95b02SDimitry Andric   NumNonEmpty = RHS.NumNonEmpty;
20591bc56edSDimitry Andric   NumTombstones = RHS.NumTombstones;
20691bc56edSDimitry Andric 
20791bc56edSDimitry Andric   // Make the RHS small and empty.
20891bc56edSDimitry Andric   RHS.CurArraySize = SmallSize;
20991bc56edSDimitry Andric   assert(RHS.CurArray == RHS.SmallArray);
2103ca95b02SDimitry Andric   RHS.NumNonEmpty = 0;
21191bc56edSDimitry Andric   RHS.NumTombstones = 0;
21291bc56edSDimitry Andric }
21391bc56edSDimitry Andric 
swap(SmallPtrSetImplBase & RHS)21491bc56edSDimitry Andric void SmallPtrSetImplBase::swap(SmallPtrSetImplBase &RHS) {
215dff0c46cSDimitry Andric   if (this == &RHS) return;
216dff0c46cSDimitry Andric 
217dff0c46cSDimitry Andric   // We can only avoid copying elements if neither set is small.
218dff0c46cSDimitry Andric   if (!this->isSmall() && !RHS.isSmall()) {
219dff0c46cSDimitry Andric     std::swap(this->CurArray, RHS.CurArray);
220dff0c46cSDimitry Andric     std::swap(this->CurArraySize, RHS.CurArraySize);
2213ca95b02SDimitry Andric     std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
222dff0c46cSDimitry Andric     std::swap(this->NumTombstones, RHS.NumTombstones);
223dff0c46cSDimitry Andric     return;
224dff0c46cSDimitry Andric   }
225dff0c46cSDimitry Andric 
226dff0c46cSDimitry Andric   // FIXME: From here on we assume that both sets have the same small size.
227dff0c46cSDimitry Andric 
228dff0c46cSDimitry Andric   // If only RHS is small, copy the small elements into LHS and move the pointer
229dff0c46cSDimitry Andric   // from LHS to RHS.
230dff0c46cSDimitry Andric   if (!this->isSmall() && RHS.isSmall()) {
2313ca95b02SDimitry Andric     assert(RHS.CurArray == RHS.SmallArray);
2323ca95b02SDimitry Andric     std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, this->SmallArray);
2333ca95b02SDimitry Andric     std::swap(RHS.CurArraySize, this->CurArraySize);
2343ca95b02SDimitry Andric     std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
2353ca95b02SDimitry Andric     std::swap(this->NumTombstones, RHS.NumTombstones);
236dff0c46cSDimitry Andric     RHS.CurArray = this->CurArray;
237dff0c46cSDimitry Andric     this->CurArray = this->SmallArray;
238dff0c46cSDimitry Andric     return;
239dff0c46cSDimitry Andric   }
240dff0c46cSDimitry Andric 
241dff0c46cSDimitry Andric   // If only LHS is small, copy the small elements into RHS and move the pointer
242dff0c46cSDimitry Andric   // from RHS to LHS.
243dff0c46cSDimitry Andric   if (this->isSmall() && !RHS.isSmall()) {
2443ca95b02SDimitry Andric     assert(this->CurArray == this->SmallArray);
2453ca95b02SDimitry Andric     std::copy(this->CurArray, this->CurArray + this->NumNonEmpty,
246dff0c46cSDimitry Andric               RHS.SmallArray);
247dff0c46cSDimitry Andric     std::swap(RHS.CurArraySize, this->CurArraySize);
2483ca95b02SDimitry Andric     std::swap(RHS.NumNonEmpty, this->NumNonEmpty);
2493ca95b02SDimitry Andric     std::swap(RHS.NumTombstones, this->NumTombstones);
250dff0c46cSDimitry Andric     this->CurArray = RHS.CurArray;
251dff0c46cSDimitry Andric     RHS.CurArray = RHS.SmallArray;
252dff0c46cSDimitry Andric     return;
253dff0c46cSDimitry Andric   }
254dff0c46cSDimitry Andric 
255dff0c46cSDimitry Andric   // Both a small, just swap the small elements.
256dff0c46cSDimitry Andric   assert(this->isSmall() && RHS.isSmall());
2573ca95b02SDimitry Andric   unsigned MinNonEmpty = std::min(this->NumNonEmpty, RHS.NumNonEmpty);
2583ca95b02SDimitry Andric   std::swap_ranges(this->SmallArray, this->SmallArray + MinNonEmpty,
259dff0c46cSDimitry Andric                    RHS.SmallArray);
2603ca95b02SDimitry Andric   if (this->NumNonEmpty > MinNonEmpty) {
2613ca95b02SDimitry Andric     std::copy(this->SmallArray + MinNonEmpty,
2623ca95b02SDimitry Andric               this->SmallArray + this->NumNonEmpty,
2633ca95b02SDimitry Andric               RHS.SmallArray + MinNonEmpty);
2643ca95b02SDimitry Andric   } else {
2653ca95b02SDimitry Andric     std::copy(RHS.SmallArray + MinNonEmpty, RHS.SmallArray + RHS.NumNonEmpty,
2663ca95b02SDimitry Andric               this->SmallArray + MinNonEmpty);
267dff0c46cSDimitry Andric   }
2683ca95b02SDimitry Andric   assert(this->CurArraySize == RHS.CurArraySize);
2693ca95b02SDimitry Andric   std::swap(this->NumNonEmpty, RHS.NumNonEmpty);
2703ca95b02SDimitry Andric   std::swap(this->NumTombstones, RHS.NumTombstones);
271f22ef01cSRoman Divacky }
272