1 //===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements the SmallPtrSet class. See SmallPtrSet.h for an 11 // overview of the algorithm. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/ADT/SmallPtrSet.h" 16 #include "llvm/Support/MathExtras.h" 17 #include <algorithm> 18 #include <cstdlib> 19 20 using namespace llvm; 21 22 void SmallPtrSetImpl::shrink_and_clear() { 23 assert(!isSmall() && "Can't shrink a small set!"); 24 free(CurArray); 25 26 // Reduce the number of buckets. 27 CurArraySize = NumElements > 16 ? 1 << (Log2_32_Ceil(NumElements) + 1) : 32; 28 NumElements = NumTombstones = 0; 29 30 // Install the new array. Clear all the buckets to empty. 31 CurArray = (const void**)malloc(sizeof(void*) * (CurArraySize+1)); 32 assert(CurArray && "Failed to allocate memory?"); 33 memset(CurArray, -1, CurArraySize*sizeof(void*)); 34 35 // The end pointer, always valid, is set to a valid element to help the 36 // iterator. 37 CurArray[CurArraySize] = 0; 38 } 39 40 bool SmallPtrSetImpl::insert_imp(const void * Ptr) { 41 if (isSmall()) { 42 // Check to see if it is already in the set. 43 for (const void **APtr = SmallArray, **E = SmallArray+NumElements; 44 APtr != E; ++APtr) 45 if (*APtr == Ptr) 46 return false; 47 48 // Nope, there isn't. If we stay small, just 'pushback' now. 49 if (NumElements < CurArraySize-1) { 50 SmallArray[NumElements++] = Ptr; 51 return true; 52 } 53 // Otherwise, hit the big set case, which will call grow. 54 } 55 56 if (NumElements*4 >= CurArraySize*3) { 57 // If more than 3/4 of the array is full, grow. 58 Grow(CurArraySize < 64 ? 128 : CurArraySize*2); 59 } else if (CurArraySize-(NumElements+NumTombstones) < CurArraySize/8) { 60 // If fewer of 1/8 of the array is empty (meaning that many are filled with 61 // tombstones), rehash. 62 Grow(CurArraySize); 63 } 64 65 // Okay, we know we have space. Find a hash bucket. 66 const void **Bucket = const_cast<const void**>(FindBucketFor(Ptr)); 67 if (*Bucket == Ptr) return false; // Already inserted, good. 68 69 // Otherwise, insert it! 70 if (*Bucket == getTombstoneMarker()) 71 --NumTombstones; 72 *Bucket = Ptr; 73 ++NumElements; // Track density. 74 return true; 75 } 76 77 bool SmallPtrSetImpl::erase_imp(const void * Ptr) { 78 if (isSmall()) { 79 // Check to see if it is in the set. 80 for (const void **APtr = SmallArray, **E = SmallArray+NumElements; 81 APtr != E; ++APtr) 82 if (*APtr == Ptr) { 83 // If it is in the set, replace this element. 84 *APtr = E[-1]; 85 E[-1] = getEmptyMarker(); 86 --NumElements; 87 return true; 88 } 89 90 return false; 91 } 92 93 // Okay, we know we have space. Find a hash bucket. 94 void **Bucket = const_cast<void**>(FindBucketFor(Ptr)); 95 if (*Bucket != Ptr) return false; // Not in the set? 96 97 // Set this as a tombstone. 98 *Bucket = getTombstoneMarker(); 99 --NumElements; 100 ++NumTombstones; 101 return true; 102 } 103 104 const void * const *SmallPtrSetImpl::FindBucketFor(const void *Ptr) const { 105 unsigned Bucket = Hash(Ptr); 106 unsigned ArraySize = CurArraySize; 107 unsigned ProbeAmt = 1; 108 const void *const *Array = CurArray; 109 const void *const *Tombstone = 0; 110 while (1) { 111 // Found Ptr's bucket? 112 if (Array[Bucket] == Ptr) 113 return Array+Bucket; 114 115 // If we found an empty bucket, the pointer doesn't exist in the set. 116 // Return a tombstone if we've seen one so far, or the empty bucket if 117 // not. 118 if (Array[Bucket] == getEmptyMarker()) 119 return Tombstone ? Tombstone : Array+Bucket; 120 121 // If this is a tombstone, remember it. If Ptr ends up not in the set, we 122 // prefer to return it than something that would require more probing. 123 if (Array[Bucket] == getTombstoneMarker() && !Tombstone) 124 Tombstone = Array+Bucket; // Remember the first tombstone found. 125 126 // It's a hash collision or a tombstone. Reprobe. 127 Bucket = (Bucket + ProbeAmt++) & (ArraySize-1); 128 } 129 } 130 131 /// Grow - Allocate a larger backing store for the buckets and move it over. 132 /// 133 void SmallPtrSetImpl::Grow(unsigned NewSize) { 134 // Allocate at twice as many buckets, but at least 128. 135 unsigned OldSize = CurArraySize; 136 137 const void **OldBuckets = CurArray; 138 bool WasSmall = isSmall(); 139 140 // Install the new array. Clear all the buckets to empty. 141 CurArray = (const void**)malloc(sizeof(void*) * (NewSize+1)); 142 assert(CurArray && "Failed to allocate memory?"); 143 CurArraySize = NewSize; 144 memset(CurArray, -1, NewSize*sizeof(void*)); 145 146 // The end pointer, always valid, is set to a valid element to help the 147 // iterator. 148 CurArray[NewSize] = 0; 149 150 // Copy over all the elements. 151 if (WasSmall) { 152 // Small sets store their elements in order. 153 for (const void **BucketPtr = OldBuckets, **E = OldBuckets+NumElements; 154 BucketPtr != E; ++BucketPtr) { 155 const void *Elt = *BucketPtr; 156 *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt); 157 } 158 } else { 159 // Copy over all valid entries. 160 for (const void **BucketPtr = OldBuckets, **E = OldBuckets+OldSize; 161 BucketPtr != E; ++BucketPtr) { 162 // Copy over the element if it is valid. 163 const void *Elt = *BucketPtr; 164 if (Elt != getTombstoneMarker() && Elt != getEmptyMarker()) 165 *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt); 166 } 167 168 free(OldBuckets); 169 NumTombstones = 0; 170 } 171 } 172 173 SmallPtrSetImpl::SmallPtrSetImpl(const void **SmallStorage, 174 const SmallPtrSetImpl& that) { 175 SmallArray = SmallStorage; 176 177 // If we're becoming small, prepare to insert into our stack space 178 if (that.isSmall()) { 179 CurArray = SmallArray; 180 // Otherwise, allocate new heap space (unless we were the same size) 181 } else { 182 CurArray = (const void**)malloc(sizeof(void*) * (that.CurArraySize+1)); 183 assert(CurArray && "Failed to allocate memory?"); 184 } 185 186 // Copy over the new array size 187 CurArraySize = that.CurArraySize; 188 189 // Copy over the contents from the other set 190 memcpy(CurArray, that.CurArray, sizeof(void*)*(CurArraySize+1)); 191 192 NumElements = that.NumElements; 193 NumTombstones = that.NumTombstones; 194 } 195 196 /// CopyFrom - implement operator= from a smallptrset that has the same pointer 197 /// type, but may have a different small size. 198 void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl &RHS) { 199 if (isSmall() && RHS.isSmall()) 200 assert(CurArraySize == RHS.CurArraySize && 201 "Cannot assign sets with different small sizes"); 202 203 // If we're becoming small, prepare to insert into our stack space 204 if (RHS.isSmall()) { 205 if (!isSmall()) 206 free(CurArray); 207 CurArray = SmallArray; 208 // Otherwise, allocate new heap space (unless we were the same size) 209 } else if (CurArraySize != RHS.CurArraySize) { 210 if (isSmall()) 211 CurArray = (const void**)malloc(sizeof(void*) * (RHS.CurArraySize+1)); 212 else 213 CurArray = (const void**)realloc(CurArray, sizeof(void*)*(RHS.CurArraySize+1)); 214 assert(CurArray && "Failed to allocate memory?"); 215 } 216 217 // Copy over the new array size 218 CurArraySize = RHS.CurArraySize; 219 220 // Copy over the contents from the other set 221 memcpy(CurArray, RHS.CurArray, sizeof(void*)*(CurArraySize+1)); 222 223 NumElements = RHS.NumElements; 224 NumTombstones = RHS.NumTombstones; 225 } 226 227 void SmallPtrSetImpl::swap(SmallPtrSetImpl &RHS) { 228 if (this == &RHS) return; 229 230 // We can only avoid copying elements if neither set is small. 231 if (!this->isSmall() && !RHS.isSmall()) { 232 std::swap(this->CurArray, RHS.CurArray); 233 std::swap(this->CurArraySize, RHS.CurArraySize); 234 std::swap(this->NumElements, RHS.NumElements); 235 std::swap(this->NumTombstones, RHS.NumTombstones); 236 return; 237 } 238 239 // FIXME: From here on we assume that both sets have the same small size. 240 241 // If only RHS is small, copy the small elements into LHS and move the pointer 242 // from LHS to RHS. 243 if (!this->isSmall() && RHS.isSmall()) { 244 std::copy(RHS.SmallArray, RHS.SmallArray+RHS.CurArraySize, 245 this->SmallArray); 246 std::swap(this->NumElements, RHS.NumElements); 247 std::swap(this->CurArraySize, RHS.CurArraySize); 248 RHS.CurArray = this->CurArray; 249 RHS.NumTombstones = this->NumTombstones; 250 this->CurArray = this->SmallArray; 251 this->NumTombstones = 0; 252 return; 253 } 254 255 // If only LHS is small, copy the small elements into RHS and move the pointer 256 // from RHS to LHS. 257 if (this->isSmall() && !RHS.isSmall()) { 258 std::copy(this->SmallArray, this->SmallArray+this->CurArraySize, 259 RHS.SmallArray); 260 std::swap(RHS.NumElements, this->NumElements); 261 std::swap(RHS.CurArraySize, this->CurArraySize); 262 this->CurArray = RHS.CurArray; 263 this->NumTombstones = RHS.NumTombstones; 264 RHS.CurArray = RHS.SmallArray; 265 RHS.NumTombstones = 0; 266 return; 267 } 268 269 // Both a small, just swap the small elements. 270 assert(this->isSmall() && RHS.isSmall()); 271 assert(this->CurArraySize == RHS.CurArraySize); 272 std::swap_ranges(this->SmallArray, this->SmallArray+this->CurArraySize, 273 RHS.SmallArray); 274 std::swap(this->NumElements, RHS.NumElements); 275 } 276 277 SmallPtrSetImpl::~SmallPtrSetImpl() { 278 if (!isSmall()) 279 free(CurArray); 280 } 281