LLVM API Documentation
00001 //===- llvm/ADT/DenseMap.h - Dense probed hash table ------------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines the DenseMap class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #ifndef LLVM_ADT_DENSEMAP_H 00015 #define LLVM_ADT_DENSEMAP_H 00016 00017 #include "llvm/ADT/DenseMapInfo.h" 00018 #include "llvm/Support/AlignOf.h" 00019 #include "llvm/Support/Compiler.h" 00020 #include "llvm/Support/MathExtras.h" 00021 #include "llvm/Support/PointerLikeTypeTraits.h" 00022 #include "llvm/Support/type_traits.h" 00023 #include <algorithm> 00024 #include <cassert> 00025 #include <climits> 00026 #include <cstddef> 00027 #include <cstring> 00028 #include <iterator> 00029 #include <new> 00030 #include <utility> 00031 00032 namespace llvm { 00033 00034 template<typename KeyT, typename ValueT, 00035 typename KeyInfoT = DenseMapInfo<KeyT>, 00036 bool IsConst = false> 00037 class DenseMapIterator; 00038 00039 template<typename DerivedT, 00040 typename KeyT, typename ValueT, typename KeyInfoT> 00041 class DenseMapBase { 00042 protected: 00043 typedef std::pair<KeyT, ValueT> BucketT; 00044 00045 public: 00046 typedef unsigned size_type; 00047 typedef KeyT key_type; 00048 typedef ValueT mapped_type; 00049 typedef BucketT value_type; 00050 00051 typedef DenseMapIterator<KeyT, ValueT, KeyInfoT> iterator; 00052 typedef DenseMapIterator<KeyT, ValueT, 00053 KeyInfoT, true> const_iterator; 00054 inline iterator begin() { 00055 // When the map is empty, avoid the overhead of AdvancePastEmptyBuckets(). 00056 return empty() ? end() : iterator(getBuckets(), getBucketsEnd()); 00057 } 00058 inline iterator end() { 00059 return iterator(getBucketsEnd(), getBucketsEnd(), true); 00060 } 00061 inline const_iterator begin() const { 00062 return empty() ? end() : const_iterator(getBuckets(), getBucketsEnd()); 00063 } 00064 inline const_iterator end() const { 00065 return const_iterator(getBucketsEnd(), getBucketsEnd(), true); 00066 } 00067 00068 bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { 00069 return getNumEntries() == 0; 00070 } 00071 unsigned size() const { return getNumEntries(); } 00072 00073 /// Grow the densemap so that it has at least Size buckets. Does not shrink 00074 void resize(size_type Size) { 00075 if (Size > getNumBuckets()) 00076 grow(Size); 00077 } 00078 00079 void clear() { 00080 if (getNumEntries() == 0 && getNumTombstones() == 0) return; 00081 00082 // If the capacity of the array is huge, and the # elements used is small, 00083 // shrink the array. 00084 if (getNumEntries() * 4 < getNumBuckets() && getNumBuckets() > 64) { 00085 shrink_and_clear(); 00086 return; 00087 } 00088 00089 const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); 00090 for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) { 00091 if (!KeyInfoT::isEqual(P->first, EmptyKey)) { 00092 if (!KeyInfoT::isEqual(P->first, TombstoneKey)) { 00093 P->second.~ValueT(); 00094 decrementNumEntries(); 00095 } 00096 P->first = EmptyKey; 00097 } 00098 } 00099 assert(getNumEntries() == 0 && "Node count imbalance!"); 00100 setNumTombstones(0); 00101 } 00102 00103 /// Return 1 if the specified key is in the map, 0 otherwise. 00104 size_type count(const KeyT &Val) const { 00105 const BucketT *TheBucket; 00106 return LookupBucketFor(Val, TheBucket) ? 1 : 0; 00107 } 00108 00109 iterator find(const KeyT &Val) { 00110 BucketT *TheBucket; 00111 if (LookupBucketFor(Val, TheBucket)) 00112 return iterator(TheBucket, getBucketsEnd(), true); 00113 return end(); 00114 } 00115 const_iterator find(const KeyT &Val) const { 00116 const BucketT *TheBucket; 00117 if (LookupBucketFor(Val, TheBucket)) 00118 return const_iterator(TheBucket, getBucketsEnd(), true); 00119 return end(); 00120 } 00121 00122 /// Alternate version of find() which allows a different, and possibly 00123 /// less expensive, key type. 00124 /// The DenseMapInfo is responsible for supplying methods 00125 /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key 00126 /// type used. 00127 template<class LookupKeyT> 00128 iterator find_as(const LookupKeyT &Val) { 00129 BucketT *TheBucket; 00130 if (LookupBucketFor(Val, TheBucket)) 00131 return iterator(TheBucket, getBucketsEnd(), true); 00132 return end(); 00133 } 00134 template<class LookupKeyT> 00135 const_iterator find_as(const LookupKeyT &Val) const { 00136 const BucketT *TheBucket; 00137 if (LookupBucketFor(Val, TheBucket)) 00138 return const_iterator(TheBucket, getBucketsEnd(), true); 00139 return end(); 00140 } 00141 00142 /// lookup - Return the entry for the specified key, or a default 00143 /// constructed value if no such entry exists. 00144 ValueT lookup(const KeyT &Val) const { 00145 const BucketT *TheBucket; 00146 if (LookupBucketFor(Val, TheBucket)) 00147 return TheBucket->second; 00148 return ValueT(); 00149 } 00150 00151 // Inserts key,value pair into the map if the key isn't already in the map. 00152 // If the key is already in the map, it returns false and doesn't update the 00153 // value. 00154 std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) { 00155 BucketT *TheBucket; 00156 if (LookupBucketFor(KV.first, TheBucket)) 00157 return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), 00158 false); // Already in map. 00159 00160 // Otherwise, insert the new element. 00161 TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket); 00162 return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true); 00163 } 00164 00165 // Inserts key,value pair into the map if the key isn't already in the map. 00166 // If the key is already in the map, it returns false and doesn't update the 00167 // value. 00168 std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) { 00169 BucketT *TheBucket; 00170 if (LookupBucketFor(KV.first, TheBucket)) 00171 return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), 00172 false); // Already in map. 00173 00174 // Otherwise, insert the new element. 00175 TheBucket = InsertIntoBucket(std::move(KV.first), 00176 std::move(KV.second), 00177 TheBucket); 00178 return std::make_pair(iterator(TheBucket, getBucketsEnd(), true), true); 00179 } 00180 00181 /// insert - Range insertion of pairs. 00182 template<typename InputIt> 00183 void insert(InputIt I, InputIt E) { 00184 for (; I != E; ++I) 00185 insert(*I); 00186 } 00187 00188 00189 bool erase(const KeyT &Val) { 00190 BucketT *TheBucket; 00191 if (!LookupBucketFor(Val, TheBucket)) 00192 return false; // not in map. 00193 00194 TheBucket->second.~ValueT(); 00195 TheBucket->first = getTombstoneKey(); 00196 decrementNumEntries(); 00197 incrementNumTombstones(); 00198 return true; 00199 } 00200 void erase(iterator I) { 00201 BucketT *TheBucket = &*I; 00202 TheBucket->second.~ValueT(); 00203 TheBucket->first = getTombstoneKey(); 00204 decrementNumEntries(); 00205 incrementNumTombstones(); 00206 } 00207 00208 value_type& FindAndConstruct(const KeyT &Key) { 00209 BucketT *TheBucket; 00210 if (LookupBucketFor(Key, TheBucket)) 00211 return *TheBucket; 00212 00213 return *InsertIntoBucket(Key, ValueT(), TheBucket); 00214 } 00215 00216 ValueT &operator[](const KeyT &Key) { 00217 return FindAndConstruct(Key).second; 00218 } 00219 00220 value_type& FindAndConstruct(KeyT &&Key) { 00221 BucketT *TheBucket; 00222 if (LookupBucketFor(Key, TheBucket)) 00223 return *TheBucket; 00224 00225 return *InsertIntoBucket(std::move(Key), ValueT(), TheBucket); 00226 } 00227 00228 ValueT &operator[](KeyT &&Key) { 00229 return FindAndConstruct(std::move(Key)).second; 00230 } 00231 00232 /// isPointerIntoBucketsArray - Return true if the specified pointer points 00233 /// somewhere into the DenseMap's array of buckets (i.e. either to a key or 00234 /// value in the DenseMap). 00235 bool isPointerIntoBucketsArray(const void *Ptr) const { 00236 return Ptr >= getBuckets() && Ptr < getBucketsEnd(); 00237 } 00238 00239 /// getPointerIntoBucketsArray() - Return an opaque pointer into the buckets 00240 /// array. In conjunction with the previous method, this can be used to 00241 /// determine whether an insertion caused the DenseMap to reallocate. 00242 const void *getPointerIntoBucketsArray() const { return getBuckets(); } 00243 00244 protected: 00245 DenseMapBase() {} 00246 00247 void destroyAll() { 00248 if (getNumBuckets() == 0) // Nothing to do. 00249 return; 00250 00251 const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); 00252 for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) { 00253 if (!KeyInfoT::isEqual(P->first, EmptyKey) && 00254 !KeyInfoT::isEqual(P->first, TombstoneKey)) 00255 P->second.~ValueT(); 00256 P->first.~KeyT(); 00257 } 00258 00259 #ifndef NDEBUG 00260 memset((void*)getBuckets(), 0x5a, sizeof(BucketT)*getNumBuckets()); 00261 #endif 00262 } 00263 00264 void initEmpty() { 00265 setNumEntries(0); 00266 setNumTombstones(0); 00267 00268 assert((getNumBuckets() & (getNumBuckets()-1)) == 0 && 00269 "# initial buckets must be a power of two!"); 00270 const KeyT EmptyKey = getEmptyKey(); 00271 for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B) 00272 new (&B->first) KeyT(EmptyKey); 00273 } 00274 00275 void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) { 00276 initEmpty(); 00277 00278 // Insert all the old elements. 00279 const KeyT EmptyKey = getEmptyKey(); 00280 const KeyT TombstoneKey = getTombstoneKey(); 00281 for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) { 00282 if (!KeyInfoT::isEqual(B->first, EmptyKey) && 00283 !KeyInfoT::isEqual(B->first, TombstoneKey)) { 00284 // Insert the key/value into the new table. 00285 BucketT *DestBucket; 00286 bool FoundVal = LookupBucketFor(B->first, DestBucket); 00287 (void)FoundVal; // silence warning. 00288 assert(!FoundVal && "Key already in new map?"); 00289 DestBucket->first = std::move(B->first); 00290 new (&DestBucket->second) ValueT(std::move(B->second)); 00291 incrementNumEntries(); 00292 00293 // Free the value. 00294 B->second.~ValueT(); 00295 } 00296 B->first.~KeyT(); 00297 } 00298 00299 #ifndef NDEBUG 00300 if (OldBucketsBegin != OldBucketsEnd) 00301 memset((void*)OldBucketsBegin, 0x5a, 00302 sizeof(BucketT) * (OldBucketsEnd - OldBucketsBegin)); 00303 #endif 00304 } 00305 00306 template <typename OtherBaseT> 00307 void copyFrom(const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT>& other) { 00308 assert(&other != this); 00309 assert(getNumBuckets() == other.getNumBuckets()); 00310 00311 setNumEntries(other.getNumEntries()); 00312 setNumTombstones(other.getNumTombstones()); 00313 00314 if (isPodLike<KeyT>::value && isPodLike<ValueT>::value) 00315 memcpy(getBuckets(), other.getBuckets(), 00316 getNumBuckets() * sizeof(BucketT)); 00317 else 00318 for (size_t i = 0; i < getNumBuckets(); ++i) { 00319 new (&getBuckets()[i].first) KeyT(other.getBuckets()[i].first); 00320 if (!KeyInfoT::isEqual(getBuckets()[i].first, getEmptyKey()) && 00321 !KeyInfoT::isEqual(getBuckets()[i].first, getTombstoneKey())) 00322 new (&getBuckets()[i].second) ValueT(other.getBuckets()[i].second); 00323 } 00324 } 00325 00326 void swap(DenseMapBase& RHS) { 00327 std::swap(getNumEntries(), RHS.getNumEntries()); 00328 std::swap(getNumTombstones(), RHS.getNumTombstones()); 00329 } 00330 00331 static unsigned getHashValue(const KeyT &Val) { 00332 return KeyInfoT::getHashValue(Val); 00333 } 00334 template<typename LookupKeyT> 00335 static unsigned getHashValue(const LookupKeyT &Val) { 00336 return KeyInfoT::getHashValue(Val); 00337 } 00338 static const KeyT getEmptyKey() { 00339 return KeyInfoT::getEmptyKey(); 00340 } 00341 static const KeyT getTombstoneKey() { 00342 return KeyInfoT::getTombstoneKey(); 00343 } 00344 00345 private: 00346 unsigned getNumEntries() const { 00347 return static_cast<const DerivedT *>(this)->getNumEntries(); 00348 } 00349 void setNumEntries(unsigned Num) { 00350 static_cast<DerivedT *>(this)->setNumEntries(Num); 00351 } 00352 void incrementNumEntries() { 00353 setNumEntries(getNumEntries() + 1); 00354 } 00355 void decrementNumEntries() { 00356 setNumEntries(getNumEntries() - 1); 00357 } 00358 unsigned getNumTombstones() const { 00359 return static_cast<const DerivedT *>(this)->getNumTombstones(); 00360 } 00361 void setNumTombstones(unsigned Num) { 00362 static_cast<DerivedT *>(this)->setNumTombstones(Num); 00363 } 00364 void incrementNumTombstones() { 00365 setNumTombstones(getNumTombstones() + 1); 00366 } 00367 void decrementNumTombstones() { 00368 setNumTombstones(getNumTombstones() - 1); 00369 } 00370 const BucketT *getBuckets() const { 00371 return static_cast<const DerivedT *>(this)->getBuckets(); 00372 } 00373 BucketT *getBuckets() { 00374 return static_cast<DerivedT *>(this)->getBuckets(); 00375 } 00376 unsigned getNumBuckets() const { 00377 return static_cast<const DerivedT *>(this)->getNumBuckets(); 00378 } 00379 BucketT *getBucketsEnd() { 00380 return getBuckets() + getNumBuckets(); 00381 } 00382 const BucketT *getBucketsEnd() const { 00383 return getBuckets() + getNumBuckets(); 00384 } 00385 00386 void grow(unsigned AtLeast) { 00387 static_cast<DerivedT *>(this)->grow(AtLeast); 00388 } 00389 00390 void shrink_and_clear() { 00391 static_cast<DerivedT *>(this)->shrink_and_clear(); 00392 } 00393 00394 00395 BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value, 00396 BucketT *TheBucket) { 00397 TheBucket = InsertIntoBucketImpl(Key, TheBucket); 00398 00399 TheBucket->first = Key; 00400 new (&TheBucket->second) ValueT(Value); 00401 return TheBucket; 00402 } 00403 00404 BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value, 00405 BucketT *TheBucket) { 00406 TheBucket = InsertIntoBucketImpl(Key, TheBucket); 00407 00408 TheBucket->first = Key; 00409 new (&TheBucket->second) ValueT(std::move(Value)); 00410 return TheBucket; 00411 } 00412 00413 BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) { 00414 TheBucket = InsertIntoBucketImpl(Key, TheBucket); 00415 00416 TheBucket->first = std::move(Key); 00417 new (&TheBucket->second) ValueT(std::move(Value)); 00418 return TheBucket; 00419 } 00420 00421 BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) { 00422 // If the load of the hash table is more than 3/4, or if fewer than 1/8 of 00423 // the buckets are empty (meaning that many are filled with tombstones), 00424 // grow the table. 00425 // 00426 // The later case is tricky. For example, if we had one empty bucket with 00427 // tons of tombstones, failing lookups (e.g. for insertion) would have to 00428 // probe almost the entire table until it found the empty bucket. If the 00429 // table completely filled with tombstones, no lookup would ever succeed, 00430 // causing infinite loops in lookup. 00431 unsigned NewNumEntries = getNumEntries() + 1; 00432 unsigned NumBuckets = getNumBuckets(); 00433 if (NewNumEntries*4 >= NumBuckets*3) { 00434 this->grow(NumBuckets * 2); 00435 LookupBucketFor(Key, TheBucket); 00436 NumBuckets = getNumBuckets(); 00437 } else if (NumBuckets-(NewNumEntries+getNumTombstones()) <= NumBuckets/8) { 00438 this->grow(NumBuckets); 00439 LookupBucketFor(Key, TheBucket); 00440 } 00441 assert(TheBucket); 00442 00443 // Only update the state after we've grown our bucket space appropriately 00444 // so that when growing buckets we have self-consistent entry count. 00445 incrementNumEntries(); 00446 00447 // If we are writing over a tombstone, remember this. 00448 const KeyT EmptyKey = getEmptyKey(); 00449 if (!KeyInfoT::isEqual(TheBucket->first, EmptyKey)) 00450 decrementNumTombstones(); 00451 00452 return TheBucket; 00453 } 00454 00455 /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in 00456 /// FoundBucket. If the bucket contains the key and a value, this returns 00457 /// true, otherwise it returns a bucket with an empty marker or tombstone and 00458 /// returns false. 00459 template<typename LookupKeyT> 00460 bool LookupBucketFor(const LookupKeyT &Val, 00461 const BucketT *&FoundBucket) const { 00462 const BucketT *BucketsPtr = getBuckets(); 00463 const unsigned NumBuckets = getNumBuckets(); 00464 00465 if (NumBuckets == 0) { 00466 FoundBucket = nullptr; 00467 return false; 00468 } 00469 00470 // FoundTombstone - Keep track of whether we find a tombstone while probing. 00471 const BucketT *FoundTombstone = nullptr; 00472 const KeyT EmptyKey = getEmptyKey(); 00473 const KeyT TombstoneKey = getTombstoneKey(); 00474 assert(!KeyInfoT::isEqual(Val, EmptyKey) && 00475 !KeyInfoT::isEqual(Val, TombstoneKey) && 00476 "Empty/Tombstone value shouldn't be inserted into map!"); 00477 00478 unsigned BucketNo = getHashValue(Val) & (NumBuckets-1); 00479 unsigned ProbeAmt = 1; 00480 while (1) { 00481 const BucketT *ThisBucket = BucketsPtr + BucketNo; 00482 // Found Val's bucket? If so, return it. 00483 if (KeyInfoT::isEqual(Val, ThisBucket->first)) { 00484 FoundBucket = ThisBucket; 00485 return true; 00486 } 00487 00488 // If we found an empty bucket, the key doesn't exist in the set. 00489 // Insert it and return the default value. 00490 if (KeyInfoT::isEqual(ThisBucket->first, EmptyKey)) { 00491 // If we've already seen a tombstone while probing, fill it in instead 00492 // of the empty bucket we eventually probed to. 00493 FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket; 00494 return false; 00495 } 00496 00497 // If this is a tombstone, remember it. If Val ends up not in the map, we 00498 // prefer to return it than something that would require more probing. 00499 if (KeyInfoT::isEqual(ThisBucket->first, TombstoneKey) && !FoundTombstone) 00500 FoundTombstone = ThisBucket; // Remember the first tombstone found. 00501 00502 // Otherwise, it's a hash collision or a tombstone, continue quadratic 00503 // probing. 00504 BucketNo += ProbeAmt++; 00505 BucketNo &= (NumBuckets-1); 00506 } 00507 } 00508 00509 template <typename LookupKeyT> 00510 bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) { 00511 const BucketT *ConstFoundBucket; 00512 bool Result = const_cast<const DenseMapBase *>(this) 00513 ->LookupBucketFor(Val, ConstFoundBucket); 00514 FoundBucket = const_cast<BucketT *>(ConstFoundBucket); 00515 return Result; 00516 } 00517 00518 public: 00519 /// Return the approximate size (in bytes) of the actual map. 00520 /// This is just the raw memory used by DenseMap. 00521 /// If entries are pointers to objects, the size of the referenced objects 00522 /// are not included. 00523 size_t getMemorySize() const { 00524 return getNumBuckets() * sizeof(BucketT); 00525 } 00526 }; 00527 00528 template<typename KeyT, typename ValueT, 00529 typename KeyInfoT = DenseMapInfo<KeyT> > 00530 class DenseMap 00531 : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT>, 00532 KeyT, ValueT, KeyInfoT> { 00533 // Lift some types from the dependent base class into this class for 00534 // simplicity of referring to them. 00535 typedef DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT> BaseT; 00536 typedef typename BaseT::BucketT BucketT; 00537 friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT>; 00538 00539 BucketT *Buckets; 00540 unsigned NumEntries; 00541 unsigned NumTombstones; 00542 unsigned NumBuckets; 00543 00544 public: 00545 explicit DenseMap(unsigned NumInitBuckets = 0) { 00546 init(NumInitBuckets); 00547 } 00548 00549 DenseMap(const DenseMap &other) : BaseT() { 00550 init(0); 00551 copyFrom(other); 00552 } 00553 00554 DenseMap(DenseMap &&other) : BaseT() { 00555 init(0); 00556 swap(other); 00557 } 00558 00559 template<typename InputIt> 00560 DenseMap(const InputIt &I, const InputIt &E) { 00561 init(NextPowerOf2(std::distance(I, E))); 00562 this->insert(I, E); 00563 } 00564 00565 ~DenseMap() { 00566 this->destroyAll(); 00567 operator delete(Buckets); 00568 } 00569 00570 void swap(DenseMap& RHS) { 00571 std::swap(Buckets, RHS.Buckets); 00572 std::swap(NumEntries, RHS.NumEntries); 00573 std::swap(NumTombstones, RHS.NumTombstones); 00574 std::swap(NumBuckets, RHS.NumBuckets); 00575 } 00576 00577 DenseMap& operator=(const DenseMap& other) { 00578 if (&other != this) 00579 copyFrom(other); 00580 return *this; 00581 } 00582 00583 DenseMap& operator=(DenseMap &&other) { 00584 this->destroyAll(); 00585 operator delete(Buckets); 00586 init(0); 00587 swap(other); 00588 return *this; 00589 } 00590 00591 void copyFrom(const DenseMap& other) { 00592 this->destroyAll(); 00593 operator delete(Buckets); 00594 if (allocateBuckets(other.NumBuckets)) { 00595 this->BaseT::copyFrom(other); 00596 } else { 00597 NumEntries = 0; 00598 NumTombstones = 0; 00599 } 00600 } 00601 00602 void init(unsigned InitBuckets) { 00603 if (allocateBuckets(InitBuckets)) { 00604 this->BaseT::initEmpty(); 00605 } else { 00606 NumEntries = 0; 00607 NumTombstones = 0; 00608 } 00609 } 00610 00611 void grow(unsigned AtLeast) { 00612 unsigned OldNumBuckets = NumBuckets; 00613 BucketT *OldBuckets = Buckets; 00614 00615 allocateBuckets(std::max<unsigned>(64, static_cast<unsigned>(NextPowerOf2(AtLeast-1)))); 00616 assert(Buckets); 00617 if (!OldBuckets) { 00618 this->BaseT::initEmpty(); 00619 return; 00620 } 00621 00622 this->moveFromOldBuckets(OldBuckets, OldBuckets+OldNumBuckets); 00623 00624 // Free the old table. 00625 operator delete(OldBuckets); 00626 } 00627 00628 void shrink_and_clear() { 00629 unsigned OldNumEntries = NumEntries; 00630 this->destroyAll(); 00631 00632 // Reduce the number of buckets. 00633 unsigned NewNumBuckets = 0; 00634 if (OldNumEntries) 00635 NewNumBuckets = std::max(64, 1 << (Log2_32_Ceil(OldNumEntries) + 1)); 00636 if (NewNumBuckets == NumBuckets) { 00637 this->BaseT::initEmpty(); 00638 return; 00639 } 00640 00641 operator delete(Buckets); 00642 init(NewNumBuckets); 00643 } 00644 00645 private: 00646 unsigned getNumEntries() const { 00647 return NumEntries; 00648 } 00649 void setNumEntries(unsigned Num) { 00650 NumEntries = Num; 00651 } 00652 00653 unsigned getNumTombstones() const { 00654 return NumTombstones; 00655 } 00656 void setNumTombstones(unsigned Num) { 00657 NumTombstones = Num; 00658 } 00659 00660 BucketT *getBuckets() const { 00661 return Buckets; 00662 } 00663 00664 unsigned getNumBuckets() const { 00665 return NumBuckets; 00666 } 00667 00668 bool allocateBuckets(unsigned Num) { 00669 NumBuckets = Num; 00670 if (NumBuckets == 0) { 00671 Buckets = nullptr; 00672 return false; 00673 } 00674 00675 Buckets = static_cast<BucketT*>(operator new(sizeof(BucketT) * NumBuckets)); 00676 return true; 00677 } 00678 }; 00679 00680 template<typename KeyT, typename ValueT, 00681 unsigned InlineBuckets = 4, 00682 typename KeyInfoT = DenseMapInfo<KeyT> > 00683 class SmallDenseMap 00684 : public DenseMapBase<SmallDenseMap<KeyT, ValueT, InlineBuckets, KeyInfoT>, 00685 KeyT, ValueT, KeyInfoT> { 00686 // Lift some types from the dependent base class into this class for 00687 // simplicity of referring to them. 00688 typedef DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT> BaseT; 00689 typedef typename BaseT::BucketT BucketT; 00690 friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT>; 00691 00692 unsigned Small : 1; 00693 unsigned NumEntries : 31; 00694 unsigned NumTombstones; 00695 00696 struct LargeRep { 00697 BucketT *Buckets; 00698 unsigned NumBuckets; 00699 }; 00700 00701 /// A "union" of an inline bucket array and the struct representing 00702 /// a large bucket. This union will be discriminated by the 'Small' bit. 00703 AlignedCharArrayUnion<BucketT[InlineBuckets], LargeRep> storage; 00704 00705 public: 00706 explicit SmallDenseMap(unsigned NumInitBuckets = 0) { 00707 init(NumInitBuckets); 00708 } 00709 00710 SmallDenseMap(const SmallDenseMap &other) : BaseT() { 00711 init(0); 00712 copyFrom(other); 00713 } 00714 00715 SmallDenseMap(SmallDenseMap &&other) : BaseT() { 00716 init(0); 00717 swap(other); 00718 } 00719 00720 template<typename InputIt> 00721 SmallDenseMap(const InputIt &I, const InputIt &E) { 00722 init(NextPowerOf2(std::distance(I, E))); 00723 this->insert(I, E); 00724 } 00725 00726 ~SmallDenseMap() { 00727 this->destroyAll(); 00728 deallocateBuckets(); 00729 } 00730 00731 void swap(SmallDenseMap& RHS) { 00732 unsigned TmpNumEntries = RHS.NumEntries; 00733 RHS.NumEntries = NumEntries; 00734 NumEntries = TmpNumEntries; 00735 std::swap(NumTombstones, RHS.NumTombstones); 00736 00737 const KeyT EmptyKey = this->getEmptyKey(); 00738 const KeyT TombstoneKey = this->getTombstoneKey(); 00739 if (Small && RHS.Small) { 00740 // If we're swapping inline bucket arrays, we have to cope with some of 00741 // the tricky bits of DenseMap's storage system: the buckets are not 00742 // fully initialized. Thus we swap every key, but we may have 00743 // a one-directional move of the value. 00744 for (unsigned i = 0, e = InlineBuckets; i != e; ++i) { 00745 BucketT *LHSB = &getInlineBuckets()[i], 00746 *RHSB = &RHS.getInlineBuckets()[i]; 00747 bool hasLHSValue = (!KeyInfoT::isEqual(LHSB->first, EmptyKey) && 00748 !KeyInfoT::isEqual(LHSB->first, TombstoneKey)); 00749 bool hasRHSValue = (!KeyInfoT::isEqual(RHSB->first, EmptyKey) && 00750 !KeyInfoT::isEqual(RHSB->first, TombstoneKey)); 00751 if (hasLHSValue && hasRHSValue) { 00752 // Swap together if we can... 00753 std::swap(*LHSB, *RHSB); 00754 continue; 00755 } 00756 // Swap separately and handle any assymetry. 00757 std::swap(LHSB->first, RHSB->first); 00758 if (hasLHSValue) { 00759 new (&RHSB->second) ValueT(std::move(LHSB->second)); 00760 LHSB->second.~ValueT(); 00761 } else if (hasRHSValue) { 00762 new (&LHSB->second) ValueT(std::move(RHSB->second)); 00763 RHSB->second.~ValueT(); 00764 } 00765 } 00766 return; 00767 } 00768 if (!Small && !RHS.Small) { 00769 std::swap(getLargeRep()->Buckets, RHS.getLargeRep()->Buckets); 00770 std::swap(getLargeRep()->NumBuckets, RHS.getLargeRep()->NumBuckets); 00771 return; 00772 } 00773 00774 SmallDenseMap &SmallSide = Small ? *this : RHS; 00775 SmallDenseMap &LargeSide = Small ? RHS : *this; 00776 00777 // First stash the large side's rep and move the small side across. 00778 LargeRep TmpRep = std::move(*LargeSide.getLargeRep()); 00779 LargeSide.getLargeRep()->~LargeRep(); 00780 LargeSide.Small = true; 00781 // This is similar to the standard move-from-old-buckets, but the bucket 00782 // count hasn't actually rotated in this case. So we have to carefully 00783 // move construct the keys and values into their new locations, but there 00784 // is no need to re-hash things. 00785 for (unsigned i = 0, e = InlineBuckets; i != e; ++i) { 00786 BucketT *NewB = &LargeSide.getInlineBuckets()[i], 00787 *OldB = &SmallSide.getInlineBuckets()[i]; 00788 new (&NewB->first) KeyT(std::move(OldB->first)); 00789 OldB->first.~KeyT(); 00790 if (!KeyInfoT::isEqual(NewB->first, EmptyKey) && 00791 !KeyInfoT::isEqual(NewB->first, TombstoneKey)) { 00792 new (&NewB->second) ValueT(std::move(OldB->second)); 00793 OldB->second.~ValueT(); 00794 } 00795 } 00796 00797 // The hard part of moving the small buckets across is done, just move 00798 // the TmpRep into its new home. 00799 SmallSide.Small = false; 00800 new (SmallSide.getLargeRep()) LargeRep(std::move(TmpRep)); 00801 } 00802 00803 SmallDenseMap& operator=(const SmallDenseMap& other) { 00804 if (&other != this) 00805 copyFrom(other); 00806 return *this; 00807 } 00808 00809 SmallDenseMap& operator=(SmallDenseMap &&other) { 00810 this->destroyAll(); 00811 deallocateBuckets(); 00812 init(0); 00813 swap(other); 00814 return *this; 00815 } 00816 00817 void copyFrom(const SmallDenseMap& other) { 00818 this->destroyAll(); 00819 deallocateBuckets(); 00820 Small = true; 00821 if (other.getNumBuckets() > InlineBuckets) { 00822 Small = false; 00823 new (getLargeRep()) LargeRep(allocateBuckets(other.getNumBuckets())); 00824 } 00825 this->BaseT::copyFrom(other); 00826 } 00827 00828 void init(unsigned InitBuckets) { 00829 Small = true; 00830 if (InitBuckets > InlineBuckets) { 00831 Small = false; 00832 new (getLargeRep()) LargeRep(allocateBuckets(InitBuckets)); 00833 } 00834 this->BaseT::initEmpty(); 00835 } 00836 00837 void grow(unsigned AtLeast) { 00838 if (AtLeast >= InlineBuckets) 00839 AtLeast = std::max<unsigned>(64, NextPowerOf2(AtLeast-1)); 00840 00841 if (Small) { 00842 if (AtLeast < InlineBuckets) 00843 return; // Nothing to do. 00844 00845 // First move the inline buckets into a temporary storage. 00846 AlignedCharArrayUnion<BucketT[InlineBuckets]> TmpStorage; 00847 BucketT *TmpBegin = reinterpret_cast<BucketT *>(TmpStorage.buffer); 00848 BucketT *TmpEnd = TmpBegin; 00849 00850 // Loop over the buckets, moving non-empty, non-tombstones into the 00851 // temporary storage. Have the loop move the TmpEnd forward as it goes. 00852 const KeyT EmptyKey = this->getEmptyKey(); 00853 const KeyT TombstoneKey = this->getTombstoneKey(); 00854 for (BucketT *P = getBuckets(), *E = P + InlineBuckets; P != E; ++P) { 00855 if (!KeyInfoT::isEqual(P->first, EmptyKey) && 00856 !KeyInfoT::isEqual(P->first, TombstoneKey)) { 00857 assert(size_t(TmpEnd - TmpBegin) < InlineBuckets && 00858 "Too many inline buckets!"); 00859 new (&TmpEnd->first) KeyT(std::move(P->first)); 00860 new (&TmpEnd->second) ValueT(std::move(P->second)); 00861 ++TmpEnd; 00862 P->second.~ValueT(); 00863 } 00864 P->first.~KeyT(); 00865 } 00866 00867 // Now make this map use the large rep, and move all the entries back 00868 // into it. 00869 Small = false; 00870 new (getLargeRep()) LargeRep(allocateBuckets(AtLeast)); 00871 this->moveFromOldBuckets(TmpBegin, TmpEnd); 00872 return; 00873 } 00874 00875 LargeRep OldRep = std::move(*getLargeRep()); 00876 getLargeRep()->~LargeRep(); 00877 if (AtLeast <= InlineBuckets) { 00878 Small = true; 00879 } else { 00880 new (getLargeRep()) LargeRep(allocateBuckets(AtLeast)); 00881 } 00882 00883 this->moveFromOldBuckets(OldRep.Buckets, OldRep.Buckets+OldRep.NumBuckets); 00884 00885 // Free the old table. 00886 operator delete(OldRep.Buckets); 00887 } 00888 00889 void shrink_and_clear() { 00890 unsigned OldSize = this->size(); 00891 this->destroyAll(); 00892 00893 // Reduce the number of buckets. 00894 unsigned NewNumBuckets = 0; 00895 if (OldSize) { 00896 NewNumBuckets = 1 << (Log2_32_Ceil(OldSize) + 1); 00897 if (NewNumBuckets > InlineBuckets && NewNumBuckets < 64u) 00898 NewNumBuckets = 64; 00899 } 00900 if ((Small && NewNumBuckets <= InlineBuckets) || 00901 (!Small && NewNumBuckets == getLargeRep()->NumBuckets)) { 00902 this->BaseT::initEmpty(); 00903 return; 00904 } 00905 00906 deallocateBuckets(); 00907 init(NewNumBuckets); 00908 } 00909 00910 private: 00911 unsigned getNumEntries() const { 00912 return NumEntries; 00913 } 00914 void setNumEntries(unsigned Num) { 00915 assert(Num < INT_MAX && "Cannot support more than INT_MAX entries"); 00916 NumEntries = Num; 00917 } 00918 00919 unsigned getNumTombstones() const { 00920 return NumTombstones; 00921 } 00922 void setNumTombstones(unsigned Num) { 00923 NumTombstones = Num; 00924 } 00925 00926 const BucketT *getInlineBuckets() const { 00927 assert(Small); 00928 // Note that this cast does not violate aliasing rules as we assert that 00929 // the memory's dynamic type is the small, inline bucket buffer, and the 00930 // 'storage.buffer' static type is 'char *'. 00931 return reinterpret_cast<const BucketT *>(storage.buffer); 00932 } 00933 BucketT *getInlineBuckets() { 00934 return const_cast<BucketT *>( 00935 const_cast<const SmallDenseMap *>(this)->getInlineBuckets()); 00936 } 00937 const LargeRep *getLargeRep() const { 00938 assert(!Small); 00939 // Note, same rule about aliasing as with getInlineBuckets. 00940 return reinterpret_cast<const LargeRep *>(storage.buffer); 00941 } 00942 LargeRep *getLargeRep() { 00943 return const_cast<LargeRep *>( 00944 const_cast<const SmallDenseMap *>(this)->getLargeRep()); 00945 } 00946 00947 const BucketT *getBuckets() const { 00948 return Small ? getInlineBuckets() : getLargeRep()->Buckets; 00949 } 00950 BucketT *getBuckets() { 00951 return const_cast<BucketT *>( 00952 const_cast<const SmallDenseMap *>(this)->getBuckets()); 00953 } 00954 unsigned getNumBuckets() const { 00955 return Small ? InlineBuckets : getLargeRep()->NumBuckets; 00956 } 00957 00958 void deallocateBuckets() { 00959 if (Small) 00960 return; 00961 00962 operator delete(getLargeRep()->Buckets); 00963 getLargeRep()->~LargeRep(); 00964 } 00965 00966 LargeRep allocateBuckets(unsigned Num) { 00967 assert(Num > InlineBuckets && "Must allocate more buckets than are inline"); 00968 LargeRep Rep = { 00969 static_cast<BucketT*>(operator new(sizeof(BucketT) * Num)), Num 00970 }; 00971 return Rep; 00972 } 00973 }; 00974 00975 template<typename KeyT, typename ValueT, 00976 typename KeyInfoT, bool IsConst> 00977 class DenseMapIterator { 00978 typedef std::pair<KeyT, ValueT> Bucket; 00979 typedef DenseMapIterator<KeyT, ValueT, 00980 KeyInfoT, true> ConstIterator; 00981 friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, true>; 00982 public: 00983 typedef ptrdiff_t difference_type; 00984 typedef typename std::conditional<IsConst, const Bucket, Bucket>::type 00985 value_type; 00986 typedef value_type *pointer; 00987 typedef value_type &reference; 00988 typedef std::forward_iterator_tag iterator_category; 00989 private: 00990 pointer Ptr, End; 00991 public: 00992 DenseMapIterator() : Ptr(nullptr), End(nullptr) {} 00993 00994 DenseMapIterator(pointer Pos, pointer E, bool NoAdvance = false) 00995 : Ptr(Pos), End(E) { 00996 if (!NoAdvance) AdvancePastEmptyBuckets(); 00997 } 00998 00999 // If IsConst is true this is a converting constructor from iterator to 01000 // const_iterator and the default copy constructor is used. 01001 // Otherwise this is a copy constructor for iterator. 01002 DenseMapIterator(const DenseMapIterator<KeyT, ValueT, 01003 KeyInfoT, false>& I) 01004 : Ptr(I.Ptr), End(I.End) {} 01005 01006 reference operator*() const { 01007 return *Ptr; 01008 } 01009 pointer operator->() const { 01010 return Ptr; 01011 } 01012 01013 bool operator==(const ConstIterator &RHS) const { 01014 return Ptr == RHS.operator->(); 01015 } 01016 bool operator!=(const ConstIterator &RHS) const { 01017 return Ptr != RHS.operator->(); 01018 } 01019 01020 inline DenseMapIterator& operator++() { // Preincrement 01021 ++Ptr; 01022 AdvancePastEmptyBuckets(); 01023 return *this; 01024 } 01025 DenseMapIterator operator++(int) { // Postincrement 01026 DenseMapIterator tmp = *this; ++*this; return tmp; 01027 } 01028 01029 private: 01030 void AdvancePastEmptyBuckets() { 01031 const KeyT Empty = KeyInfoT::getEmptyKey(); 01032 const KeyT Tombstone = KeyInfoT::getTombstoneKey(); 01033 01034 while (Ptr != End && 01035 (KeyInfoT::isEqual(Ptr->first, Empty) || 01036 KeyInfoT::isEqual(Ptr->first, Tombstone))) 01037 ++Ptr; 01038 } 01039 }; 01040 01041 template<typename KeyT, typename ValueT, typename KeyInfoT> 01042 static inline size_t 01043 capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) { 01044 return X.getMemorySize(); 01045 } 01046 01047 } // end namespace llvm 01048 01049 #endif