LLVM API Documentation

DenseMap.h

Go to the documentation of this file.
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/Support/DataTypes.h"
00018 #include "llvm/Support/MathExtras.h"
00019 #include <cassert>
00020 #include <utility>
00021 
00022 namespace llvm {
00023   
00024 template<typename T>
00025 struct DenseMapInfo {
00026   //static inline T getEmptyKey();
00027   //static inline T getTombstoneKey();
00028   //static unsigned getHashValue(const T &Val);
00029   //static bool isEqual(const T &LHS, const T &RHS);
00030   //static bool isPod()
00031 };
00032 
00033 // Provide DenseMapInfo for all pointers.
00034 template<typename T>
00035 struct DenseMapInfo<T*> {
00036   static inline T* getEmptyKey() { return reinterpret_cast<T*>(-1); }
00037   static inline T* getTombstoneKey() { return reinterpret_cast<T*>(-2); }
00038   static unsigned getHashValue(const T *PtrVal) {
00039     return (unsigned((uintptr_t)PtrVal) >> 4) ^ 
00040            (unsigned((uintptr_t)PtrVal) >> 9);
00041   }
00042   static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }
00043   static bool isPod() { return true; }
00044 };
00045 
00046 // Provide DenseMapInfo for unsigned ints.
00047 template<> struct DenseMapInfo<uint32_t> {
00048   static inline uint32_t getEmptyKey() { return ~0; }
00049   static inline uint32_t getTombstoneKey() { return ~0 - 1; }
00050   static unsigned getHashValue(const uint32_t& Val) { return Val * 37; }
00051   static bool isPod() { return true; }
00052   static bool isEqual(const uint32_t& LHS, const uint32_t& RHS) {
00053   return LHS == RHS;
00054   }
00055 };
00056 
00057 // Provide DenseMapInfo for all pairs whose members have info.
00058 template<typename T, typename U>
00059 struct DenseMapInfo<std::pair<T, U> > {
00060   typedef std::pair<T, U> Pair;
00061   typedef DenseMapInfo<T> FirstInfo;
00062   typedef DenseMapInfo<U> SecondInfo;
00063 
00064   static inline Pair getEmptyKey() { 
00065     return std::make_pair(FirstInfo::getEmptyKey(), 
00066                           SecondInfo::getEmptyKey()); 
00067   }
00068   static inline Pair getTombstoneKey() { 
00069     return std::make_pair(FirstInfo::getTombstoneKey(), 
00070                             SecondInfo::getEmptyKey());
00071   }
00072   static unsigned getHashValue(const Pair& PairVal) {
00073     uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32
00074           | (uint64_t)SecondInfo::getHashValue(PairVal.second);
00075     key += ~(key << 32);
00076     key ^= (key >> 22);
00077     key += ~(key << 13);
00078     key ^= (key >> 8);
00079     key += (key << 3);
00080     key ^= (key >> 15);
00081     key += ~(key << 27);
00082     key ^= (key >> 31);
00083     return (unsigned)key;
00084   }
00085   static bool isEqual(const Pair& LHS, const Pair& RHS) { return LHS == RHS; }
00086   static bool isPod() { return FirstInfo::isPod() && SecondInfo::isPod(); }
00087 };
00088 
00089 template<typename KeyT, typename ValueT, 
00090          typename KeyInfoT = DenseMapInfo<KeyT>,
00091          typename ValueInfoT = DenseMapInfo<ValueT> >
00092 class DenseMapIterator;
00093 template<typename KeyT, typename ValueT,
00094          typename KeyInfoT = DenseMapInfo<KeyT>,
00095          typename ValueInfoT = DenseMapInfo<ValueT> >
00096 class DenseMapConstIterator;
00097 
00098 template<typename KeyT, typename ValueT,
00099          typename KeyInfoT = DenseMapInfo<KeyT>,
00100          typename ValueInfoT = DenseMapInfo<ValueT> >
00101 class DenseMap {
00102   typedef std::pair<KeyT, ValueT> BucketT;
00103   unsigned NumBuckets;
00104   BucketT *Buckets;
00105   
00106   unsigned NumEntries;
00107   unsigned NumTombstones;
00108 public:
00109   typedef KeyT key_type;
00110   typedef ValueT mapped_type;
00111   typedef BucketT value_type;
00112   
00113   DenseMap(const DenseMap& other) {
00114     NumBuckets = 0;
00115     CopyFrom(other);
00116   }
00117   
00118   explicit DenseMap(unsigned NumInitBuckets = 64) {
00119     init(NumInitBuckets);
00120   }
00121   
00122   ~DenseMap() {
00123     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
00124     for (BucketT *P = Buckets, *E = Buckets+NumBuckets; P != E; ++P) {
00125       if (!KeyInfoT::isEqual(P->first, EmptyKey) &&
00126           !KeyInfoT::isEqual(P->first, TombstoneKey))
00127         P->second.~ValueT();
00128       P->first.~KeyT();
00129     }
00130     operator delete(Buckets);
00131   }
00132   
00133   typedef DenseMapIterator<KeyT, ValueT, KeyInfoT> iterator;
00134   typedef DenseMapConstIterator<KeyT, ValueT, KeyInfoT> const_iterator;
00135   inline iterator begin() {
00136      return iterator(Buckets, Buckets+NumBuckets);
00137   }
00138   inline iterator end() {
00139     return iterator(Buckets+NumBuckets, Buckets+NumBuckets);
00140   }
00141   inline const_iterator begin() const {
00142     return const_iterator(Buckets, Buckets+NumBuckets);
00143   }
00144   inline const_iterator end() const {
00145     return const_iterator(Buckets+NumBuckets, Buckets+NumBuckets);
00146   }
00147   
00148   bool empty() const { return NumEntries == 0; }
00149   unsigned size() const { return NumEntries; }
00150 
00151   /// Grow the densemap so that it has at least Size buckets. Does not shrink
00152   void resize(size_t Size) { grow(Size); }
00153   
00154   void clear() {
00155     // If the capacity of the array is huge, and the # elements used is small,
00156     // shrink the array.
00157     if (NumEntries * 4 < NumBuckets && NumBuckets > 64) {
00158       shrink_and_clear();
00159       return;
00160     }
00161     
00162     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
00163     for (BucketT *P = Buckets, *E = Buckets+NumBuckets; P != E; ++P) {
00164       if (!KeyInfoT::isEqual(P->first, EmptyKey)) {
00165         if (!KeyInfoT::isEqual(P->first, TombstoneKey)) {
00166           P->second.~ValueT();
00167           --NumEntries;
00168         }
00169         P->first = EmptyKey;
00170       }
00171     }
00172     assert(NumEntries == 0 && "Node count imbalance!");
00173     NumTombstones = 0;
00174   }
00175 
00176   /// count - Return true if the specified key is in the map.
00177   bool count(const KeyT &Val) const {
00178     BucketT *TheBucket;
00179     return LookupBucketFor(Val, TheBucket);
00180   }
00181   
00182   iterator find(const KeyT &Val) {
00183     BucketT *TheBucket;
00184     if (LookupBucketFor(Val, TheBucket))
00185       return iterator(TheBucket, Buckets+NumBuckets);
00186     return end();
00187   }
00188   const_iterator find(const KeyT &Val) const {
00189     BucketT *TheBucket;
00190     if (LookupBucketFor(Val, TheBucket))
00191       return const_iterator(TheBucket, Buckets+NumBuckets);
00192     return end();
00193   }
00194   
00195   /// lookup - Return the entry for the specified key, or a default
00196   /// constructed value if no such entry exists.
00197   ValueT lookup(const KeyT &Val) const {
00198     BucketT *TheBucket;
00199     if (LookupBucketFor(Val, TheBucket))
00200       return TheBucket->second;
00201     return ValueT();
00202   }
00203 
00204   std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
00205     BucketT *TheBucket;
00206     if (LookupBucketFor(KV.first, TheBucket))
00207       return std::make_pair(iterator(TheBucket, Buckets+NumBuckets),
00208                             false); // Already in map.
00209     
00210     // Otherwise, insert the new element.
00211     TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket);
00212     return std::make_pair(iterator(TheBucket, Buckets+NumBuckets),
00213                           true);
00214   }
00215   
00216   /// insert - Range insertion of pairs.
00217   template<typename InputIt>
00218   void insert(InputIt I, InputIt E) {
00219     for (; I != E; ++I)
00220       insert(*I);
00221   }
00222 
00223   
00224   bool erase(const KeyT &Val) {
00225     BucketT *TheBucket;
00226     if (!LookupBucketFor(Val, TheBucket))
00227       return false; // not in map.
00228 
00229     TheBucket->second.~ValueT();
00230     TheBucket->first = getTombstoneKey();
00231     --NumEntries;
00232     ++NumTombstones;
00233     return true;
00234   }
00235   bool erase(iterator I) {
00236     BucketT *TheBucket = &*I;
00237     TheBucket->second.~ValueT();
00238     TheBucket->first = getTombstoneKey();
00239     --NumEntries;
00240     ++NumTombstones;
00241     return true;
00242   }
00243 
00244   value_type& FindAndConstruct(const KeyT &Key) {
00245     BucketT *TheBucket;
00246     if (LookupBucketFor(Key, TheBucket))
00247       return *TheBucket;
00248     
00249     return *InsertIntoBucket(Key, ValueT(), TheBucket);
00250   }
00251   
00252   ValueT &operator[](const KeyT &Key) {
00253     return FindAndConstruct(Key).second;
00254   }
00255   
00256   DenseMap& operator=(const DenseMap& other) {
00257     CopyFrom(other);
00258     return *this;
00259   }
00260   
00261 private:
00262   void CopyFrom(const DenseMap& other) {
00263     if (NumBuckets != 0 && (!KeyInfoT::isPod() || !ValueInfoT::isPod())) {
00264       const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
00265       for (BucketT *P = Buckets, *E = Buckets+NumBuckets; P != E; ++P) {
00266         if (!KeyInfoT::isEqual(P->first, EmptyKey) &&
00267             !KeyInfoT::isEqual(P->first, TombstoneKey))
00268           P->second.~ValueT();
00269         P->first.~KeyT();
00270       }
00271     }
00272     
00273     NumEntries = other.NumEntries;
00274     NumTombstones = other.NumTombstones;
00275     
00276     if (NumBuckets)
00277       operator delete(Buckets);
00278     Buckets = static_cast<BucketT*>(operator new(sizeof(BucketT) *
00279                                                  other.NumBuckets));
00280     
00281     if (KeyInfoT::isPod() && ValueInfoT::isPod())
00282       memcpy(Buckets, other.Buckets, other.NumBuckets * sizeof(BucketT));
00283     else
00284       for (size_t i = 0; i < other.NumBuckets; ++i) {
00285         new (&Buckets[i].first) KeyT(other.Buckets[i].first);
00286         if (!KeyInfoT::isEqual(Buckets[i].first, getEmptyKey()) &&
00287             !KeyInfoT::isEqual(Buckets[i].first, getTombstoneKey()))
00288           new (&Buckets[i].second) ValueT(other.Buckets[i].second);
00289       }
00290     NumBuckets = other.NumBuckets;
00291   }
00292   
00293   BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,
00294                             BucketT *TheBucket) {
00295     // If the load of the hash table is more than 3/4, or if fewer than 1/8 of
00296     // the buckets are empty (meaning that many are filled with tombstones),
00297     // grow the table.
00298     //
00299     // The later case is tricky.  For example, if we had one empty bucket with
00300     // tons of tombstones, failing lookups (e.g. for insertion) would have to
00301     // probe almost the entire table until it found the empty bucket.  If the
00302     // table completely filled with tombstones, no lookup would ever succeed,
00303     // causing infinite loops in lookup.
00304     if (NumEntries*4 >= NumBuckets*3 ||
00305         NumBuckets-(NumEntries+NumTombstones) < NumBuckets/8) {        
00306       this->grow(NumBuckets * 2);
00307       LookupBucketFor(Key, TheBucket);
00308     }
00309     ++NumEntries;
00310     
00311     // If we are writing over a tombstone, remember this.
00312     if (!KeyInfoT::isEqual(TheBucket->first, getEmptyKey()))
00313       --NumTombstones;
00314     
00315     TheBucket->first = Key;
00316     new (&TheBucket->second) ValueT(Value);
00317     return TheBucket;
00318   }
00319 
00320   static unsigned getHashValue(const KeyT &Val) {
00321     return KeyInfoT::getHashValue(Val);
00322   }
00323   static const KeyT getEmptyKey() {
00324     return KeyInfoT::getEmptyKey();
00325   }
00326   static const KeyT getTombstoneKey() {
00327     return KeyInfoT::getTombstoneKey();
00328   }
00329   
00330   /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in
00331   /// FoundBucket.  If the bucket contains the key and a value, this returns
00332   /// true, otherwise it returns a bucket with an empty marker or tombstone and
00333   /// returns false.
00334   bool LookupBucketFor(const KeyT &Val, BucketT *&FoundBucket) const {
00335     unsigned BucketNo = getHashValue(Val);
00336     unsigned ProbeAmt = 1;
00337     BucketT *BucketsPtr = Buckets;
00338     
00339     // FoundTombstone - Keep track of whether we find a tombstone while probing.
00340     BucketT *FoundTombstone = 0;
00341     const KeyT EmptyKey = getEmptyKey();
00342     const KeyT TombstoneKey = getTombstoneKey();
00343     assert(!KeyInfoT::isEqual(Val, EmptyKey) &&
00344            !KeyInfoT::isEqual(Val, TombstoneKey) &&
00345            "Empty/Tombstone value shouldn't be inserted into map!");
00346       
00347     while (1) {
00348       BucketT *ThisBucket = BucketsPtr + (BucketNo & (NumBuckets-1));
00349       // Found Val's bucket?  If so, return it.
00350       if (KeyInfoT::isEqual(ThisBucket->first, Val)) {
00351         FoundBucket = ThisBucket;
00352         return true;
00353       }
00354       
00355       // If we found an empty bucket, the key doesn't exist in the set.
00356       // Insert it and return the default value.
00357       if (KeyInfoT::isEqual(ThisBucket->first, EmptyKey)) {
00358         // If we've already seen a tombstone while probing, fill it in instead
00359         // of the empty bucket we eventually probed to.
00360         if (FoundTombstone) ThisBucket = FoundTombstone;
00361         FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
00362         return false;
00363       }
00364       
00365       // If this is a tombstone, remember it.  If Val ends up not in the map, we
00366       // prefer to return it than something that would require more probing.
00367       if (KeyInfoT::isEqual(ThisBucket->first, TombstoneKey) && !FoundTombstone)
00368         FoundTombstone = ThisBucket;  // Remember the first tombstone found.
00369       
00370       // Otherwise, it's a hash collision or a tombstone, continue quadratic
00371       // probing.
00372       BucketNo += ProbeAmt++;
00373     }
00374   }
00375 
00376   void init(unsigned InitBuckets) {
00377     NumEntries = 0;
00378     NumTombstones = 0;
00379     NumBuckets = InitBuckets;
00380     assert(InitBuckets && (InitBuckets & (InitBuckets-1)) == 0 &&
00381            "# initial buckets must be a power of two!");
00382     Buckets = static_cast<BucketT*>(operator new(sizeof(BucketT)*InitBuckets));
00383     // Initialize all the keys to EmptyKey.
00384     const KeyT EmptyKey = getEmptyKey();
00385     for (unsigned i = 0; i != InitBuckets; ++i)
00386       new (&Buckets[i].first) KeyT(EmptyKey);
00387   }
00388   
00389   void grow(unsigned AtLeast) {
00390     unsigned OldNumBuckets = NumBuckets;
00391     BucketT *OldBuckets = Buckets;
00392     
00393     // Double the number of buckets.
00394     while (NumBuckets <= AtLeast)
00395       NumBuckets <<= 1;
00396     NumTombstones = 0;
00397     Buckets = static_cast<BucketT*>(operator new(sizeof(BucketT)*NumBuckets));
00398 
00399     // Initialize all the keys to EmptyKey.
00400     const KeyT EmptyKey = getEmptyKey();
00401     for (unsigned i = 0, e = NumBuckets; i != e; ++i)
00402       new (&Buckets[i].first) KeyT(EmptyKey);
00403 
00404     // Insert all the old elements.
00405     const KeyT TombstoneKey = getTombstoneKey();
00406     for (BucketT *B = OldBuckets, *E = OldBuckets+OldNumBuckets; B != E; ++B) {
00407       if (!KeyInfoT::isEqual(B->first, EmptyKey) &&
00408           !KeyInfoT::isEqual(B->first, TombstoneKey)) {
00409         // Insert the key/value into the new table.
00410         BucketT *DestBucket;
00411         bool FoundVal = LookupBucketFor(B->first, DestBucket);
00412         FoundVal = FoundVal; // silence warning.
00413         assert(!FoundVal && "Key already in new map?");
00414         DestBucket->first = B->first;
00415         new (&DestBucket->second) ValueT(B->second);
00416         
00417         // Free the value.
00418         B->second.~ValueT();
00419       }
00420       B->first.~KeyT();
00421     }
00422     
00423     // Free the old table.
00424     operator delete(OldBuckets);
00425   }
00426   
00427   void shrink_and_clear() {
00428     unsigned OldNumBuckets = NumBuckets;
00429     BucketT *OldBuckets = Buckets;
00430     
00431     // Reduce the number of buckets.
00432     NumBuckets = NumEntries > 32 ? 1 << (Log2_32_Ceil(NumEntries) + 1)
00433                                  : 64;
00434     NumTombstones = 0;
00435     Buckets = static_cast<BucketT*>(operator new(sizeof(BucketT)*NumBuckets));
00436 
00437     // Initialize all the keys to EmptyKey.
00438     const KeyT EmptyKey = getEmptyKey();
00439     for (unsigned i = 0, e = NumBuckets; i != e; ++i)
00440       new (&Buckets[i].first) KeyT(EmptyKey);
00441 
00442     // Free the old buckets.
00443     const KeyT TombstoneKey = getTombstoneKey();
00444     for (BucketT *B = OldBuckets, *E = OldBuckets+OldNumBuckets; B != E; ++B) {
00445       if (!KeyInfoT::isEqual(B->first, EmptyKey) &&
00446           !KeyInfoT::isEqual(B->first, TombstoneKey)) {
00447         // Free the value.
00448         B->second.~ValueT();
00449       }
00450       B->first.~KeyT();
00451     }
00452     
00453     // Free the old table.
00454     operator delete(OldBuckets);
00455     
00456     NumEntries = 0;
00457   }
00458 };
00459 
00460 template<typename KeyT, typename ValueT, typename KeyInfoT, typename ValueInfoT>
00461 class DenseMapIterator {
00462   typedef std::pair<KeyT, ValueT> BucketT;
00463 protected:
00464   const BucketT *Ptr, *End;
00465 public:
00466   DenseMapIterator(void) : Ptr(0), End(0) {}
00467 
00468   DenseMapIterator(const BucketT *Pos, const BucketT *E) : Ptr(Pos), End(E) {
00469     AdvancePastEmptyBuckets();
00470   }
00471   
00472   std::pair<KeyT, ValueT> &operator*() const {
00473     return *const_cast<BucketT*>(Ptr);
00474   }
00475   std::pair<KeyT, ValueT> *operator->() const {
00476     return const_cast<BucketT*>(Ptr);
00477   }
00478   
00479   bool operator==(const DenseMapIterator &RHS) const {
00480     return Ptr == RHS.Ptr;
00481   }
00482   bool operator!=(const DenseMapIterator &RHS) const {
00483     return Ptr != RHS.Ptr;
00484   }
00485   
00486   inline DenseMapIterator& operator++() {          // Preincrement
00487     ++Ptr;
00488     AdvancePastEmptyBuckets();
00489     return *this;
00490   }
00491   DenseMapIterator operator++(int) {        // Postincrement
00492     DenseMapIterator tmp = *this; ++*this; return tmp;
00493   }
00494   
00495 private:
00496   void AdvancePastEmptyBuckets() {
00497     const KeyT Empty = KeyInfoT::getEmptyKey();
00498     const KeyT Tombstone = KeyInfoT::getTombstoneKey();
00499 
00500     while (Ptr != End && 
00501            (KeyInfoT::isEqual(Ptr->first, Empty) ||
00502             KeyInfoT::isEqual(Ptr->first, Tombstone)))
00503       ++Ptr;
00504   }
00505 };
00506 
00507 template<typename KeyT, typename ValueT, typename KeyInfoT, typename ValueInfoT>
00508 class DenseMapConstIterator : public DenseMapIterator<KeyT, ValueT, KeyInfoT> {
00509 public:
00510   DenseMapConstIterator(void) : DenseMapIterator<KeyT, ValueT, KeyInfoT>() {}
00511   DenseMapConstIterator(const std::pair<KeyT, ValueT> *Pos,
00512                         const std::pair<KeyT, ValueT> *E)
00513     : DenseMapIterator<KeyT, ValueT, KeyInfoT>(Pos, E) {
00514   }
00515   const std::pair<KeyT, ValueT> &operator*() const {
00516     return *this->Ptr;
00517   }
00518   const std::pair<KeyT, ValueT> *operator->() const {
00519     return this->Ptr;
00520   }
00521 };
00522 
00523 } // end namespace llvm
00524 
00525 #endif



This web site is hosted by the Computer Science Department at the University of Illinois at Urbana-Champaign.