50cdefd2c3f908f1649c0be7b83ab33c1a6ba9d5
[oota-llvm.git] / include / llvm / ADT / DenseMap.h
1 //===- llvm/ADT/DenseMap.h - Dense probed hash table ------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by Chris Lattner and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines the DenseMap class.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_ADT_DENSEMAP_H
15 #define LLVM_ADT_DENSEMAP_H
16
17 #include "llvm/Support/DataTypes.h"
18 #include <cassert>
19 #include <utility>
20
21 namespace llvm {
22   
23 template<typename T>
24 struct DenseMapKeyInfo {
25   //static inline T getEmptyKey();
26   //static inline T getTombstoneKey();
27   //static unsigned getHashValue(const T &Val);
28   //static bool isPod()
29 };
30
31 template<typename T>
32 struct DenseMapKeyInfo<T*> {
33   static inline T* getEmptyKey() { return (T*)-1; }
34   static inline T* getTombstoneKey() { return (T*)-2; }
35   static unsigned getHashValue(const T *PtrVal) {
36     return (unsigned)((uintptr_t)PtrVal >> 4) ^
37            (unsigned)((uintptr_t)PtrVal >> 9);
38   }
39   static bool isPod() { return true; }
40 };
41
42 template<typename KeyT, typename ValueT>
43 class DenseMapIterator;
44
45 template<typename KeyT, typename ValueT>
46 class DenseMap {
47   typedef std::pair<KeyT, ValueT> BucketT;
48   unsigned NumBuckets;
49   BucketT *Buckets;
50   
51   unsigned NumEntries;
52   DenseMap(const DenseMap &); // not implemented.
53 public:
54   explicit DenseMap(unsigned NumInitBuckets = 8) {
55     init(NumInitBuckets);
56   }
57   ~DenseMap() {
58     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
59     for (BucketT *P = Buckets, *E = Buckets+NumBuckets; P != E; ++P) {
60       if (P->first != EmptyKey && P->first != TombstoneKey)
61         P->second.~ValueT();
62       P->first.~KeyT();
63     }
64     delete[] (char*)Buckets;
65   }
66   
67   typedef DenseMapIterator<KeyT, ValueT> iterator;
68   typedef DenseMapIterator<KeyT, ValueT> const_iterator;
69   inline iterator begin() const;
70   inline iterator end() const;
71   
72   unsigned size() const { return NumEntries; }
73   
74   void clear() {
75     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
76     for (BucketT *P = Buckets, *E = Buckets+NumBuckets; P != E; ++P) {
77       if (P->first != EmptyKey && P->first != TombstoneKey) {
78         P->first = EmptyKey;
79         P->second.~ValueT();
80         --NumEntries;
81       }
82     }
83     assert(NumEntries == 0 && "Node count imbalance!");
84   }
85   
86   /// count - Return true if the specified key is in the map.
87   bool count(const KeyT &Val) const {
88     BucketT *TheBucket;
89     return LookupBucketFor(Val, TheBucket);
90   }
91   
92   ValueT &operator[](const KeyT &Val) {
93     BucketT *TheBucket;
94     if (LookupBucketFor(Val, TheBucket))
95       return TheBucket->second;
96
97     // If the load of the hash table is more than 3/4, grow it.
98     if (NumEntries*4 >= NumBuckets*3) {
99       this->grow();
100       LookupBucketFor(Val, TheBucket);
101     }
102     ++NumEntries;
103     TheBucket->first = Val;
104     new (&TheBucket->second) ValueT();
105     return TheBucket->second;
106   }
107   
108 private:
109   unsigned getHashValue(const KeyT &Val) const {
110     return DenseMapKeyInfo<KeyT>::getHashValue(Val);
111   }
112   const KeyT getEmptyKey() const { return DenseMapKeyInfo<KeyT>::getEmptyKey();}
113   const KeyT getTombstoneKey() const {
114     return DenseMapKeyInfo<KeyT>::getTombstoneKey();
115   }
116   
117   /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in
118   /// FoundBucket.  If the bucket contains the key and a value, this returns
119   /// true, otherwise it returns a bucket with an empty marker or tombstone and
120   /// returns false.
121   bool LookupBucketFor(const KeyT &Val, BucketT *&FoundBucket) const {
122     unsigned BucketNo = getHashValue(Val);
123     unsigned ProbeAmt = 1;
124     BucketT *BucketsPtr = Buckets;
125     
126     // FoundTombstone - Keep track of whether we find a tombstone while probing.
127     BucketT *FoundTombstone = 0;
128     const KeyT EmptyKey = getEmptyKey();
129     const KeyT TombstoneKey = getTombstoneKey();
130     assert(Val != EmptyKey && Val != TombstoneKey &&
131            "Empty/Tombstone value shouldn't be inserted into map!");
132       
133     while (1) {
134       BucketT *ThisBucket = BucketsPtr + (BucketNo & (NumBuckets-1));
135       // Found Val's bucket?  If so, return it.
136       if (ThisBucket->first == Val) {
137         FoundBucket = ThisBucket;
138         return true;
139       }
140       
141       // If we found an empty bucket, the key doesn't exist in the set.
142       // Insert it and return the default value.
143       if (ThisBucket->first == EmptyKey) {
144         // If we've already seen a tombstone while probing, fill it in instead
145         // of the empty bucket we eventually probed to.
146         if (FoundTombstone) ThisBucket = FoundTombstone;
147         FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
148         return false;
149       }
150       
151       // If this is a tombstone, remember it.  If Val ends up not in the map, we
152       // prefer to return it than something that would require more probing.
153       if (ThisBucket->first == TombstoneKey && !FoundTombstone)
154         FoundTombstone = ThisBucket;  // Remember the first tombstone found.
155       
156       // Otherwise, it's a hash collision or a tombstone, continue quadratic
157       // probing.
158       BucketNo += ProbeAmt++;
159     }
160   }
161
162   void init(unsigned InitBuckets) {
163     NumEntries = 0;
164     NumBuckets = InitBuckets;
165     assert(InitBuckets && (InitBuckets & InitBuckets-1) == 0 &&
166            "# initial buckets must be a power of two!");
167     Buckets = (BucketT*)new char[sizeof(BucketT)*InitBuckets];
168     // Initialize all the keys to EmptyKey.
169     const KeyT EmptyKey = getEmptyKey();
170     for (unsigned i = 0; i != InitBuckets; ++i)
171       new (&Buckets[i].first) KeyT(EmptyKey);
172   }
173   
174   void grow() {
175     unsigned OldNumBuckets = NumBuckets;
176     BucketT *OldBuckets = Buckets;
177     
178     // Double the number of buckets.
179     NumBuckets <<= 1;
180     Buckets = (BucketT*)new char[sizeof(BucketT)*NumBuckets];
181
182     // Initialize all the keys to EmptyKey.
183     const KeyT EmptyKey = getEmptyKey();
184     for (unsigned i = 0, e = NumBuckets; i != e; ++i)
185       new (&Buckets[i].first) KeyT(EmptyKey);
186
187     // Insert all the old elements.
188     const KeyT TombstoneKey = getTombstoneKey();
189     for (BucketT *B = OldBuckets, *E = OldBuckets+OldNumBuckets; B != E; ++B) {
190       if (B->first != EmptyKey && B->first != TombstoneKey) {
191         // Insert the key/value into the new table.
192         BucketT *DestBucket;
193         bool FoundVal = LookupBucketFor(B->first, DestBucket);
194         assert(!FoundVal && "Key already in new map?");
195         DestBucket->first = B->first;
196         new (&DestBucket->second) ValueT(B->second);
197         
198         // Free the value.
199         B->second.~ValueT();
200       }
201       B->first.~KeyT();
202     }
203     
204     // Free the old table.
205     delete[] (char*)OldBuckets;
206   }
207 };
208
209 template<typename KeyT, typename ValueT>
210 class DenseMapIterator {
211   typedef std::pair<KeyT, ValueT> BucketT;
212   const BucketT *Ptr, *End;
213 public:
214   DenseMapIterator(const BucketT *Pos, const BucketT *E) : Ptr(Pos), End(E) {
215     AdvancePastEmptyBuckets();
216   }
217   
218   const std::pair<KeyT, ValueT> &operator*() const {
219     return *Ptr;
220   }
221   const std::pair<KeyT, ValueT> *operator->() const {
222     return Ptr;
223   }
224   
225   bool operator==(const DenseMapIterator &RHS) const {
226     return Ptr == RHS.Ptr;
227   }
228   bool operator!=(const DenseMapIterator &RHS) const {
229     return Ptr != RHS.Ptr;
230   }
231   
232   inline DenseMapIterator& operator++() {          // Preincrement
233     ++Ptr;
234     AdvancePastEmptyBuckets();
235     return *this;
236   }
237   DenseMapIterator operator++(int) {        // Postincrement
238     DenseMapIterator tmp = *this; ++*this; return tmp;
239   }
240   
241 private:
242   void AdvancePastEmptyBuckets() {
243     const KeyT Empty = DenseMapKeyInfo<KeyT>::getEmptyKey();
244     const KeyT Tombstone = DenseMapKeyInfo<KeyT>::getTombstoneKey();
245
246     while (Ptr != End && Ptr->first != Empty && Ptr->first != Tombstone)
247       ++Ptr;
248   }
249 };
250
251
252 template<typename KeyT, typename ValueT>
253 inline DenseMapIterator<KeyT, ValueT> DenseMap<KeyT, ValueT>::begin() const {
254   return DenseMapIterator<KeyT, ValueT>(Buckets, Buckets+NumBuckets);
255 }
256 template<typename KeyT, typename ValueT>
257 inline DenseMapIterator<KeyT, ValueT> DenseMap<KeyT, ValueT>::end() const {
258   return DenseMapIterator<KeyT, ValueT>(Buckets+NumBuckets, Buckets+NumBuckets);
259 }
260
261 } // end namespace llvm
262
263 #endif