xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_dense_map.h (revision 4824e7fd18a1223177218d4aec1b3c6c5c4a444e)
1349cc55cSDimitry Andric //===- sanitizer_dense_map.h - Dense probed hash table ----------*- C++ -*-===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric //
9349cc55cSDimitry Andric // This is fork of llvm/ADT/DenseMap.h class with the following changes:
10349cc55cSDimitry Andric //  * Use mmap to allocate.
11349cc55cSDimitry Andric //  * No iterators.
12349cc55cSDimitry Andric //  * Does not shrink.
13349cc55cSDimitry Andric //
14349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
15349cc55cSDimitry Andric 
16349cc55cSDimitry Andric #ifndef SANITIZER_DENSE_MAP_H
17349cc55cSDimitry Andric #define SANITIZER_DENSE_MAP_H
18349cc55cSDimitry Andric 
19349cc55cSDimitry Andric #include "sanitizer_common.h"
20349cc55cSDimitry Andric #include "sanitizer_dense_map_info.h"
21349cc55cSDimitry Andric #include "sanitizer_internal_defs.h"
22349cc55cSDimitry Andric #include "sanitizer_type_traits.h"
23349cc55cSDimitry Andric 
24349cc55cSDimitry Andric namespace __sanitizer {
25349cc55cSDimitry Andric 
26349cc55cSDimitry Andric template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
27349cc55cSDimitry Andric           typename BucketT>
28349cc55cSDimitry Andric class DenseMapBase {
29349cc55cSDimitry Andric  public:
30349cc55cSDimitry Andric   using size_type = unsigned;
31349cc55cSDimitry Andric   using key_type = KeyT;
32349cc55cSDimitry Andric   using mapped_type = ValueT;
33349cc55cSDimitry Andric   using value_type = BucketT;
34349cc55cSDimitry Andric 
empty()35349cc55cSDimitry Andric   WARN_UNUSED_RESULT bool empty() const { return getNumEntries() == 0; }
size()36349cc55cSDimitry Andric   unsigned size() const { return getNumEntries(); }
37349cc55cSDimitry Andric 
38349cc55cSDimitry Andric   /// Grow the densemap so that it can contain at least \p NumEntries items
39349cc55cSDimitry Andric   /// before resizing again.
reserve(size_type NumEntries)40349cc55cSDimitry Andric   void reserve(size_type NumEntries) {
41349cc55cSDimitry Andric     auto NumBuckets = getMinBucketToReserveForEntries(NumEntries);
42349cc55cSDimitry Andric     if (NumBuckets > getNumBuckets())
43349cc55cSDimitry Andric       grow(NumBuckets);
44349cc55cSDimitry Andric   }
45349cc55cSDimitry Andric 
clear()46349cc55cSDimitry Andric   void clear() {
47349cc55cSDimitry Andric     if (getNumEntries() == 0 && getNumTombstones() == 0)
48349cc55cSDimitry Andric       return;
49349cc55cSDimitry Andric 
50349cc55cSDimitry Andric     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
51349cc55cSDimitry Andric     if (__sanitizer::is_trivially_destructible<ValueT>::value) {
52349cc55cSDimitry Andric       // Use a simpler loop when values don't need destruction.
53349cc55cSDimitry Andric       for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
54349cc55cSDimitry Andric         P->getFirst() = EmptyKey;
55349cc55cSDimitry Andric     } else {
56349cc55cSDimitry Andric       unsigned NumEntries = getNumEntries();
57349cc55cSDimitry Andric       for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
58349cc55cSDimitry Andric         if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
59349cc55cSDimitry Andric           if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
60349cc55cSDimitry Andric             P->getSecond().~ValueT();
61349cc55cSDimitry Andric             --NumEntries;
62349cc55cSDimitry Andric           }
63349cc55cSDimitry Andric           P->getFirst() = EmptyKey;
64349cc55cSDimitry Andric         }
65349cc55cSDimitry Andric       }
66349cc55cSDimitry Andric       CHECK_EQ(NumEntries, 0);
67349cc55cSDimitry Andric     }
68349cc55cSDimitry Andric     setNumEntries(0);
69349cc55cSDimitry Andric     setNumTombstones(0);
70349cc55cSDimitry Andric   }
71349cc55cSDimitry Andric 
72349cc55cSDimitry Andric   /// Return 1 if the specified key is in the map, 0 otherwise.
count(const KeyT & Key)73349cc55cSDimitry Andric   size_type count(const KeyT &Key) const {
74349cc55cSDimitry Andric     const BucketT *TheBucket;
75349cc55cSDimitry Andric     return LookupBucketFor(Key, TheBucket) ? 1 : 0;
76349cc55cSDimitry Andric   }
77349cc55cSDimitry Andric 
find(const KeyT & Key)78349cc55cSDimitry Andric   value_type *find(const KeyT &Key) {
79349cc55cSDimitry Andric     BucketT *TheBucket;
80349cc55cSDimitry Andric     if (LookupBucketFor(Key, TheBucket))
81349cc55cSDimitry Andric       return TheBucket;
82349cc55cSDimitry Andric     return nullptr;
83349cc55cSDimitry Andric   }
find(const KeyT & Key)84349cc55cSDimitry Andric   const value_type *find(const KeyT &Key) const {
85349cc55cSDimitry Andric     const BucketT *TheBucket;
86349cc55cSDimitry Andric     if (LookupBucketFor(Key, TheBucket))
87349cc55cSDimitry Andric       return TheBucket;
88349cc55cSDimitry Andric     return nullptr;
89349cc55cSDimitry Andric   }
90349cc55cSDimitry Andric 
91349cc55cSDimitry Andric   /// Alternate version of find() which allows a different, and possibly
92349cc55cSDimitry Andric   /// less expensive, key type.
93349cc55cSDimitry Andric   /// The DenseMapInfo is responsible for supplying methods
94349cc55cSDimitry Andric   /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key
95349cc55cSDimitry Andric   /// type used.
96349cc55cSDimitry Andric   template <class LookupKeyT>
find_as(const LookupKeyT & Key)97349cc55cSDimitry Andric   value_type *find_as(const LookupKeyT &Key) {
98349cc55cSDimitry Andric     BucketT *TheBucket;
99349cc55cSDimitry Andric     if (LookupBucketFor(Key, TheBucket))
100349cc55cSDimitry Andric       return TheBucket;
101349cc55cSDimitry Andric     return nullptr;
102349cc55cSDimitry Andric   }
103349cc55cSDimitry Andric   template <class LookupKeyT>
find_as(const LookupKeyT & Key)104349cc55cSDimitry Andric   const value_type *find_as(const LookupKeyT &Key) const {
105349cc55cSDimitry Andric     const BucketT *TheBucket;
106349cc55cSDimitry Andric     if (LookupBucketFor(Key, TheBucket))
107349cc55cSDimitry Andric       return TheBucket;
108349cc55cSDimitry Andric     return nullptr;
109349cc55cSDimitry Andric   }
110349cc55cSDimitry Andric 
111349cc55cSDimitry Andric   /// lookup - Return the entry for the specified key, or a default
112349cc55cSDimitry Andric   /// constructed value if no such entry exists.
lookup(const KeyT & Key)113349cc55cSDimitry Andric   ValueT lookup(const KeyT &Key) const {
114349cc55cSDimitry Andric     const BucketT *TheBucket;
115349cc55cSDimitry Andric     if (LookupBucketFor(Key, TheBucket))
116349cc55cSDimitry Andric       return TheBucket->getSecond();
117349cc55cSDimitry Andric     return ValueT();
118349cc55cSDimitry Andric   }
119349cc55cSDimitry Andric 
120349cc55cSDimitry Andric   // Inserts key,value pair into the map if the key isn't already in the map.
121349cc55cSDimitry Andric   // If the key is already in the map, it returns false and doesn't update the
122349cc55cSDimitry Andric   // value.
insert(const value_type & KV)123349cc55cSDimitry Andric   detail::DenseMapPair<value_type *, bool> insert(const value_type &KV) {
124349cc55cSDimitry Andric     return try_emplace(KV.first, KV.second);
125349cc55cSDimitry Andric   }
126349cc55cSDimitry Andric 
127349cc55cSDimitry Andric   // Inserts key,value pair into the map if the key isn't already in the map.
128349cc55cSDimitry Andric   // If the key is already in the map, it returns false and doesn't update the
129349cc55cSDimitry Andric   // value.
insert(value_type && KV)130349cc55cSDimitry Andric   detail::DenseMapPair<value_type *, bool> insert(value_type &&KV) {
131349cc55cSDimitry Andric     return try_emplace(__sanitizer::move(KV.first),
132349cc55cSDimitry Andric                        __sanitizer::move(KV.second));
133349cc55cSDimitry Andric   }
134349cc55cSDimitry Andric 
135349cc55cSDimitry Andric   // Inserts key,value pair into the map if the key isn't already in the map.
136349cc55cSDimitry Andric   // The value is constructed in-place if the key is not in the map, otherwise
137349cc55cSDimitry Andric   // it is not moved.
138349cc55cSDimitry Andric   template <typename... Ts>
try_emplace(KeyT && Key,Ts &&...Args)139349cc55cSDimitry Andric   detail::DenseMapPair<value_type *, bool> try_emplace(KeyT &&Key,
140349cc55cSDimitry Andric                                                        Ts &&...Args) {
141349cc55cSDimitry Andric     BucketT *TheBucket;
142349cc55cSDimitry Andric     if (LookupBucketFor(Key, TheBucket))
143349cc55cSDimitry Andric       return {TheBucket, false};  // Already in map.
144349cc55cSDimitry Andric 
145349cc55cSDimitry Andric     // Otherwise, insert the new element.
146349cc55cSDimitry Andric     TheBucket = InsertIntoBucket(TheBucket, __sanitizer::move(Key),
147349cc55cSDimitry Andric                                  __sanitizer::forward<Ts>(Args)...);
148349cc55cSDimitry Andric     return {TheBucket, true};
149349cc55cSDimitry Andric   }
150349cc55cSDimitry Andric 
151349cc55cSDimitry Andric   // Inserts key,value pair into the map if the key isn't already in the map.
152349cc55cSDimitry Andric   // The value is constructed in-place if the key is not in the map, otherwise
153349cc55cSDimitry Andric   // it is not moved.
154349cc55cSDimitry Andric   template <typename... Ts>
try_emplace(const KeyT & Key,Ts &&...Args)155349cc55cSDimitry Andric   detail::DenseMapPair<value_type *, bool> try_emplace(const KeyT &Key,
156349cc55cSDimitry Andric                                                        Ts &&...Args) {
157349cc55cSDimitry Andric     BucketT *TheBucket;
158349cc55cSDimitry Andric     if (LookupBucketFor(Key, TheBucket))
159349cc55cSDimitry Andric       return {TheBucket, false};  // Already in map.
160349cc55cSDimitry Andric 
161349cc55cSDimitry Andric     // Otherwise, insert the new element.
162349cc55cSDimitry Andric     TheBucket =
163349cc55cSDimitry Andric         InsertIntoBucket(TheBucket, Key, __sanitizer::forward<Ts>(Args)...);
164349cc55cSDimitry Andric     return {TheBucket, true};
165349cc55cSDimitry Andric   }
166349cc55cSDimitry Andric 
167349cc55cSDimitry Andric   /// Alternate version of insert() which allows a different, and possibly
168349cc55cSDimitry Andric   /// less expensive, key type.
169349cc55cSDimitry Andric   /// The DenseMapInfo is responsible for supplying methods
170349cc55cSDimitry Andric   /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key
171349cc55cSDimitry Andric   /// type used.
172349cc55cSDimitry Andric   template <typename LookupKeyT>
insert_as(value_type && KV,const LookupKeyT & Val)173349cc55cSDimitry Andric   detail::DenseMapPair<value_type *, bool> insert_as(value_type &&KV,
174349cc55cSDimitry Andric                                                      const LookupKeyT &Val) {
175349cc55cSDimitry Andric     BucketT *TheBucket;
176349cc55cSDimitry Andric     if (LookupBucketFor(Val, TheBucket))
177349cc55cSDimitry Andric       return {TheBucket, false};  // Already in map.
178349cc55cSDimitry Andric 
179349cc55cSDimitry Andric     // Otherwise, insert the new element.
180349cc55cSDimitry Andric     TheBucket =
181349cc55cSDimitry Andric         InsertIntoBucketWithLookup(TheBucket, __sanitizer::move(KV.first),
182349cc55cSDimitry Andric                                    __sanitizer::move(KV.second), Val);
183349cc55cSDimitry Andric     return {TheBucket, true};
184349cc55cSDimitry Andric   }
185349cc55cSDimitry Andric 
erase(const KeyT & Val)186349cc55cSDimitry Andric   bool erase(const KeyT &Val) {
187349cc55cSDimitry Andric     BucketT *TheBucket;
188349cc55cSDimitry Andric     if (!LookupBucketFor(Val, TheBucket))
189349cc55cSDimitry Andric       return false;  // not in map.
190349cc55cSDimitry Andric 
191349cc55cSDimitry Andric     TheBucket->getSecond().~ValueT();
192349cc55cSDimitry Andric     TheBucket->getFirst() = getTombstoneKey();
193349cc55cSDimitry Andric     decrementNumEntries();
194349cc55cSDimitry Andric     incrementNumTombstones();
195349cc55cSDimitry Andric     return true;
196349cc55cSDimitry Andric   }
197349cc55cSDimitry Andric 
erase(value_type * I)198349cc55cSDimitry Andric   void erase(value_type *I) {
199349cc55cSDimitry Andric     CHECK_NE(I, nullptr);
200349cc55cSDimitry Andric     BucketT *TheBucket = &*I;
201349cc55cSDimitry Andric     TheBucket->getSecond().~ValueT();
202349cc55cSDimitry Andric     TheBucket->getFirst() = getTombstoneKey();
203349cc55cSDimitry Andric     decrementNumEntries();
204349cc55cSDimitry Andric     incrementNumTombstones();
205349cc55cSDimitry Andric   }
206349cc55cSDimitry Andric 
FindAndConstruct(const KeyT & Key)207349cc55cSDimitry Andric   value_type &FindAndConstruct(const KeyT &Key) {
208349cc55cSDimitry Andric     BucketT *TheBucket;
209349cc55cSDimitry Andric     if (LookupBucketFor(Key, TheBucket))
210349cc55cSDimitry Andric       return *TheBucket;
211349cc55cSDimitry Andric 
212349cc55cSDimitry Andric     return *InsertIntoBucket(TheBucket, Key);
213349cc55cSDimitry Andric   }
214349cc55cSDimitry Andric 
215349cc55cSDimitry Andric   ValueT &operator[](const KeyT &Key) { return FindAndConstruct(Key).second; }
216349cc55cSDimitry Andric 
FindAndConstruct(KeyT && Key)217349cc55cSDimitry Andric   value_type &FindAndConstruct(KeyT &&Key) {
218349cc55cSDimitry Andric     BucketT *TheBucket;
219349cc55cSDimitry Andric     if (LookupBucketFor(Key, TheBucket))
220349cc55cSDimitry Andric       return *TheBucket;
221349cc55cSDimitry Andric 
222349cc55cSDimitry Andric     return *InsertIntoBucket(TheBucket, __sanitizer::move(Key));
223349cc55cSDimitry Andric   }
224349cc55cSDimitry Andric 
225349cc55cSDimitry Andric   ValueT &operator[](KeyT &&Key) {
226349cc55cSDimitry Andric     return FindAndConstruct(__sanitizer::move(Key)).second;
227349cc55cSDimitry Andric   }
228349cc55cSDimitry Andric 
229*4824e7fdSDimitry Andric   /// Iterate over active entries of the container.
230349cc55cSDimitry Andric   ///
231*4824e7fdSDimitry Andric   /// Function can return fast to stop the process.
232*4824e7fdSDimitry Andric   template <class Fn>
forEach(Fn fn)233*4824e7fdSDimitry Andric   void forEach(Fn fn) {
234349cc55cSDimitry Andric     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
235349cc55cSDimitry Andric     for (auto *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
236349cc55cSDimitry Andric       const KeyT K = P->getFirst();
237349cc55cSDimitry Andric       if (!KeyInfoT::isEqual(K, EmptyKey) &&
238349cc55cSDimitry Andric           !KeyInfoT::isEqual(K, TombstoneKey)) {
239*4824e7fdSDimitry Andric         if (!fn(*P))
240*4824e7fdSDimitry Andric           return;
241*4824e7fdSDimitry Andric       }
242349cc55cSDimitry Andric     }
243349cc55cSDimitry Andric   }
244349cc55cSDimitry Andric 
245*4824e7fdSDimitry Andric   template <class Fn>
forEach(Fn fn)246*4824e7fdSDimitry Andric   void forEach(Fn fn) const {
247*4824e7fdSDimitry Andric     const_cast<DenseMapBase *>(this)->forEach(
248*4824e7fdSDimitry Andric         [&](const value_type &KV) { return fn(KV); });
249349cc55cSDimitry Andric   }
250349cc55cSDimitry Andric 
251349cc55cSDimitry Andric  protected:
252349cc55cSDimitry Andric   DenseMapBase() = default;
253349cc55cSDimitry Andric 
destroyAll()254349cc55cSDimitry Andric   void destroyAll() {
255349cc55cSDimitry Andric     if (getNumBuckets() == 0)  // Nothing to do.
256349cc55cSDimitry Andric       return;
257349cc55cSDimitry Andric 
258349cc55cSDimitry Andric     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
259349cc55cSDimitry Andric     for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
260349cc55cSDimitry Andric       if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) &&
261349cc55cSDimitry Andric           !KeyInfoT::isEqual(P->getFirst(), TombstoneKey))
262349cc55cSDimitry Andric         P->getSecond().~ValueT();
263349cc55cSDimitry Andric       P->getFirst().~KeyT();
264349cc55cSDimitry Andric     }
265349cc55cSDimitry Andric   }
266349cc55cSDimitry Andric 
initEmpty()267349cc55cSDimitry Andric   void initEmpty() {
268349cc55cSDimitry Andric     setNumEntries(0);
269349cc55cSDimitry Andric     setNumTombstones(0);
270349cc55cSDimitry Andric 
271349cc55cSDimitry Andric     CHECK_EQ((getNumBuckets() & (getNumBuckets() - 1)), 0);
272349cc55cSDimitry Andric     const KeyT EmptyKey = getEmptyKey();
273349cc55cSDimitry Andric     for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B)
274349cc55cSDimitry Andric       ::new (&B->getFirst()) KeyT(EmptyKey);
275349cc55cSDimitry Andric   }
276349cc55cSDimitry Andric 
277349cc55cSDimitry Andric   /// Returns the number of buckets to allocate to ensure that the DenseMap can
278349cc55cSDimitry Andric   /// accommodate \p NumEntries without need to grow().
getMinBucketToReserveForEntries(unsigned NumEntries)279349cc55cSDimitry Andric   unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
280349cc55cSDimitry Andric     // Ensure that "NumEntries * 4 < NumBuckets * 3"
281349cc55cSDimitry Andric     if (NumEntries == 0)
282349cc55cSDimitry Andric       return 0;
283349cc55cSDimitry Andric     // +1 is required because of the strict equality.
284349cc55cSDimitry Andric     // For example if NumEntries is 48, we need to return 401.
285349cc55cSDimitry Andric     return RoundUpToPowerOfTwo((NumEntries * 4 / 3 + 1) + /* NextPowerOf2 */ 1);
286349cc55cSDimitry Andric   }
287349cc55cSDimitry Andric 
moveFromOldBuckets(BucketT * OldBucketsBegin,BucketT * OldBucketsEnd)288349cc55cSDimitry Andric   void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) {
289349cc55cSDimitry Andric     initEmpty();
290349cc55cSDimitry Andric 
291349cc55cSDimitry Andric     // Insert all the old elements.
292349cc55cSDimitry Andric     const KeyT EmptyKey = getEmptyKey();
293349cc55cSDimitry Andric     const KeyT TombstoneKey = getTombstoneKey();
294349cc55cSDimitry Andric     for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) {
295349cc55cSDimitry Andric       if (!KeyInfoT::isEqual(B->getFirst(), EmptyKey) &&
296349cc55cSDimitry Andric           !KeyInfoT::isEqual(B->getFirst(), TombstoneKey)) {
297349cc55cSDimitry Andric         // Insert the key/value into the new table.
298349cc55cSDimitry Andric         BucketT *DestBucket;
299349cc55cSDimitry Andric         bool FoundVal = LookupBucketFor(B->getFirst(), DestBucket);
300349cc55cSDimitry Andric         (void)FoundVal;  // silence warning.
301349cc55cSDimitry Andric         CHECK(!FoundVal);
302349cc55cSDimitry Andric         DestBucket->getFirst() = __sanitizer::move(B->getFirst());
303349cc55cSDimitry Andric         ::new (&DestBucket->getSecond())
304349cc55cSDimitry Andric             ValueT(__sanitizer::move(B->getSecond()));
305349cc55cSDimitry Andric         incrementNumEntries();
306349cc55cSDimitry Andric 
307349cc55cSDimitry Andric         // Free the value.
308349cc55cSDimitry Andric         B->getSecond().~ValueT();
309349cc55cSDimitry Andric       }
310349cc55cSDimitry Andric       B->getFirst().~KeyT();
311349cc55cSDimitry Andric     }
312349cc55cSDimitry Andric   }
313349cc55cSDimitry Andric 
314349cc55cSDimitry Andric   template <typename OtherBaseT>
copyFrom(const DenseMapBase<OtherBaseT,KeyT,ValueT,KeyInfoT,BucketT> & other)315349cc55cSDimitry Andric   void copyFrom(
316349cc55cSDimitry Andric       const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT, BucketT> &other) {
317349cc55cSDimitry Andric     CHECK_NE(&other, this);
318349cc55cSDimitry Andric     CHECK_EQ(getNumBuckets(), other.getNumBuckets());
319349cc55cSDimitry Andric 
320349cc55cSDimitry Andric     setNumEntries(other.getNumEntries());
321349cc55cSDimitry Andric     setNumTombstones(other.getNumTombstones());
322349cc55cSDimitry Andric 
323349cc55cSDimitry Andric     if (__sanitizer::is_trivially_copyable<KeyT>::value &&
324349cc55cSDimitry Andric         __sanitizer::is_trivially_copyable<ValueT>::value)
325349cc55cSDimitry Andric       internal_memcpy(reinterpret_cast<void *>(getBuckets()),
326349cc55cSDimitry Andric                       other.getBuckets(), getNumBuckets() * sizeof(BucketT));
327349cc55cSDimitry Andric     else
328349cc55cSDimitry Andric       for (uptr i = 0; i < getNumBuckets(); ++i) {
329349cc55cSDimitry Andric         ::new (&getBuckets()[i].getFirst())
330349cc55cSDimitry Andric             KeyT(other.getBuckets()[i].getFirst());
331349cc55cSDimitry Andric         if (!KeyInfoT::isEqual(getBuckets()[i].getFirst(), getEmptyKey()) &&
332349cc55cSDimitry Andric             !KeyInfoT::isEqual(getBuckets()[i].getFirst(), getTombstoneKey()))
333349cc55cSDimitry Andric           ::new (&getBuckets()[i].getSecond())
334349cc55cSDimitry Andric               ValueT(other.getBuckets()[i].getSecond());
335349cc55cSDimitry Andric       }
336349cc55cSDimitry Andric   }
337349cc55cSDimitry Andric 
getHashValue(const KeyT & Val)338349cc55cSDimitry Andric   static unsigned getHashValue(const KeyT &Val) {
339349cc55cSDimitry Andric     return KeyInfoT::getHashValue(Val);
340349cc55cSDimitry Andric   }
341349cc55cSDimitry Andric 
342349cc55cSDimitry Andric   template <typename LookupKeyT>
getHashValue(const LookupKeyT & Val)343349cc55cSDimitry Andric   static unsigned getHashValue(const LookupKeyT &Val) {
344349cc55cSDimitry Andric     return KeyInfoT::getHashValue(Val);
345349cc55cSDimitry Andric   }
346349cc55cSDimitry Andric 
getEmptyKey()347349cc55cSDimitry Andric   static const KeyT getEmptyKey() { return KeyInfoT::getEmptyKey(); }
348349cc55cSDimitry Andric 
getTombstoneKey()349349cc55cSDimitry Andric   static const KeyT getTombstoneKey() { return KeyInfoT::getTombstoneKey(); }
350349cc55cSDimitry Andric 
351349cc55cSDimitry Andric  private:
getNumEntries()352349cc55cSDimitry Andric   unsigned getNumEntries() const {
353349cc55cSDimitry Andric     return static_cast<const DerivedT *>(this)->getNumEntries();
354349cc55cSDimitry Andric   }
355349cc55cSDimitry Andric 
setNumEntries(unsigned Num)356349cc55cSDimitry Andric   void setNumEntries(unsigned Num) {
357349cc55cSDimitry Andric     static_cast<DerivedT *>(this)->setNumEntries(Num);
358349cc55cSDimitry Andric   }
359349cc55cSDimitry Andric 
incrementNumEntries()360349cc55cSDimitry Andric   void incrementNumEntries() { setNumEntries(getNumEntries() + 1); }
361349cc55cSDimitry Andric 
decrementNumEntries()362349cc55cSDimitry Andric   void decrementNumEntries() { setNumEntries(getNumEntries() - 1); }
363349cc55cSDimitry Andric 
getNumTombstones()364349cc55cSDimitry Andric   unsigned getNumTombstones() const {
365349cc55cSDimitry Andric     return static_cast<const DerivedT *>(this)->getNumTombstones();
366349cc55cSDimitry Andric   }
367349cc55cSDimitry Andric 
setNumTombstones(unsigned Num)368349cc55cSDimitry Andric   void setNumTombstones(unsigned Num) {
369349cc55cSDimitry Andric     static_cast<DerivedT *>(this)->setNumTombstones(Num);
370349cc55cSDimitry Andric   }
371349cc55cSDimitry Andric 
incrementNumTombstones()372349cc55cSDimitry Andric   void incrementNumTombstones() { setNumTombstones(getNumTombstones() + 1); }
373349cc55cSDimitry Andric 
decrementNumTombstones()374349cc55cSDimitry Andric   void decrementNumTombstones() { setNumTombstones(getNumTombstones() - 1); }
375349cc55cSDimitry Andric 
getBuckets()376349cc55cSDimitry Andric   const BucketT *getBuckets() const {
377349cc55cSDimitry Andric     return static_cast<const DerivedT *>(this)->getBuckets();
378349cc55cSDimitry Andric   }
379349cc55cSDimitry Andric 
getBuckets()380349cc55cSDimitry Andric   BucketT *getBuckets() { return static_cast<DerivedT *>(this)->getBuckets(); }
381349cc55cSDimitry Andric 
getNumBuckets()382349cc55cSDimitry Andric   unsigned getNumBuckets() const {
383349cc55cSDimitry Andric     return static_cast<const DerivedT *>(this)->getNumBuckets();
384349cc55cSDimitry Andric   }
385349cc55cSDimitry Andric 
getBucketsEnd()386349cc55cSDimitry Andric   BucketT *getBucketsEnd() { return getBuckets() + getNumBuckets(); }
387349cc55cSDimitry Andric 
getBucketsEnd()388349cc55cSDimitry Andric   const BucketT *getBucketsEnd() const {
389349cc55cSDimitry Andric     return getBuckets() + getNumBuckets();
390349cc55cSDimitry Andric   }
391349cc55cSDimitry Andric 
grow(unsigned AtLeast)392349cc55cSDimitry Andric   void grow(unsigned AtLeast) { static_cast<DerivedT *>(this)->grow(AtLeast); }
393349cc55cSDimitry Andric 
394349cc55cSDimitry Andric   template <typename KeyArg, typename... ValueArgs>
InsertIntoBucket(BucketT * TheBucket,KeyArg && Key,ValueArgs &&...Values)395349cc55cSDimitry Andric   BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
396349cc55cSDimitry Andric                             ValueArgs &&...Values) {
397349cc55cSDimitry Andric     TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
398349cc55cSDimitry Andric 
399349cc55cSDimitry Andric     TheBucket->getFirst() = __sanitizer::forward<KeyArg>(Key);
400349cc55cSDimitry Andric     ::new (&TheBucket->getSecond())
401349cc55cSDimitry Andric         ValueT(__sanitizer::forward<ValueArgs>(Values)...);
402349cc55cSDimitry Andric     return TheBucket;
403349cc55cSDimitry Andric   }
404349cc55cSDimitry Andric 
405349cc55cSDimitry Andric   template <typename LookupKeyT>
InsertIntoBucketWithLookup(BucketT * TheBucket,KeyT && Key,ValueT && Value,LookupKeyT & Lookup)406349cc55cSDimitry Andric   BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key,
407349cc55cSDimitry Andric                                       ValueT &&Value, LookupKeyT &Lookup) {
408349cc55cSDimitry Andric     TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);
409349cc55cSDimitry Andric 
410349cc55cSDimitry Andric     TheBucket->getFirst() = __sanitizer::move(Key);
411349cc55cSDimitry Andric     ::new (&TheBucket->getSecond()) ValueT(__sanitizer::move(Value));
412349cc55cSDimitry Andric     return TheBucket;
413349cc55cSDimitry Andric   }
414349cc55cSDimitry Andric 
415349cc55cSDimitry Andric   template <typename LookupKeyT>
InsertIntoBucketImpl(const KeyT & Key,const LookupKeyT & Lookup,BucketT * TheBucket)416349cc55cSDimitry Andric   BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup,
417349cc55cSDimitry Andric                                 BucketT *TheBucket) {
418349cc55cSDimitry Andric     // If the load of the hash table is more than 3/4, or if fewer than 1/8 of
419349cc55cSDimitry Andric     // the buckets are empty (meaning that many are filled with tombstones),
420349cc55cSDimitry Andric     // grow the table.
421349cc55cSDimitry Andric     //
422349cc55cSDimitry Andric     // The later case is tricky.  For example, if we had one empty bucket with
423349cc55cSDimitry Andric     // tons of tombstones, failing lookups (e.g. for insertion) would have to
424349cc55cSDimitry Andric     // probe almost the entire table until it found the empty bucket.  If the
425349cc55cSDimitry Andric     // table completely filled with tombstones, no lookup would ever succeed,
426349cc55cSDimitry Andric     // causing infinite loops in lookup.
427349cc55cSDimitry Andric     unsigned NewNumEntries = getNumEntries() + 1;
428349cc55cSDimitry Andric     unsigned NumBuckets = getNumBuckets();
429349cc55cSDimitry Andric     if (UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) {
430349cc55cSDimitry Andric       this->grow(NumBuckets * 2);
431349cc55cSDimitry Andric       LookupBucketFor(Lookup, TheBucket);
432349cc55cSDimitry Andric       NumBuckets = getNumBuckets();
433349cc55cSDimitry Andric     } else if (UNLIKELY(NumBuckets - (NewNumEntries + getNumTombstones()) <=
434349cc55cSDimitry Andric                         NumBuckets / 8)) {
435349cc55cSDimitry Andric       this->grow(NumBuckets);
436349cc55cSDimitry Andric       LookupBucketFor(Lookup, TheBucket);
437349cc55cSDimitry Andric     }
438349cc55cSDimitry Andric     CHECK(TheBucket);
439349cc55cSDimitry Andric 
440349cc55cSDimitry Andric     // Only update the state after we've grown our bucket space appropriately
441349cc55cSDimitry Andric     // so that when growing buckets we have self-consistent entry count.
442349cc55cSDimitry Andric     incrementNumEntries();
443349cc55cSDimitry Andric 
444349cc55cSDimitry Andric     // If we are writing over a tombstone, remember this.
445349cc55cSDimitry Andric     const KeyT EmptyKey = getEmptyKey();
446349cc55cSDimitry Andric     if (!KeyInfoT::isEqual(TheBucket->getFirst(), EmptyKey))
447349cc55cSDimitry Andric       decrementNumTombstones();
448349cc55cSDimitry Andric 
449349cc55cSDimitry Andric     return TheBucket;
450349cc55cSDimitry Andric   }
451349cc55cSDimitry Andric 
452349cc55cSDimitry Andric   /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in
453349cc55cSDimitry Andric   /// FoundBucket.  If the bucket contains the key and a value, this returns
454349cc55cSDimitry Andric   /// true, otherwise it returns a bucket with an empty marker or tombstone and
455349cc55cSDimitry Andric   /// returns false.
456349cc55cSDimitry Andric   template <typename LookupKeyT>
LookupBucketFor(const LookupKeyT & Val,const BucketT * & FoundBucket)457349cc55cSDimitry Andric   bool LookupBucketFor(const LookupKeyT &Val,
458349cc55cSDimitry Andric                        const BucketT *&FoundBucket) const {
459349cc55cSDimitry Andric     const BucketT *BucketsPtr = getBuckets();
460349cc55cSDimitry Andric     const unsigned NumBuckets = getNumBuckets();
461349cc55cSDimitry Andric 
462349cc55cSDimitry Andric     if (NumBuckets == 0) {
463349cc55cSDimitry Andric       FoundBucket = nullptr;
464349cc55cSDimitry Andric       return false;
465349cc55cSDimitry Andric     }
466349cc55cSDimitry Andric 
467349cc55cSDimitry Andric     // FoundTombstone - Keep track of whether we find a tombstone while probing.
468349cc55cSDimitry Andric     const BucketT *FoundTombstone = nullptr;
469349cc55cSDimitry Andric     const KeyT EmptyKey = getEmptyKey();
470349cc55cSDimitry Andric     const KeyT TombstoneKey = getTombstoneKey();
471349cc55cSDimitry Andric     CHECK(!KeyInfoT::isEqual(Val, EmptyKey));
472349cc55cSDimitry Andric     CHECK(!KeyInfoT::isEqual(Val, TombstoneKey));
473349cc55cSDimitry Andric 
474349cc55cSDimitry Andric     unsigned BucketNo = getHashValue(Val) & (NumBuckets - 1);
475349cc55cSDimitry Andric     unsigned ProbeAmt = 1;
476349cc55cSDimitry Andric     while (true) {
477349cc55cSDimitry Andric       const BucketT *ThisBucket = BucketsPtr + BucketNo;
478349cc55cSDimitry Andric       // Found Val's bucket?  If so, return it.
479349cc55cSDimitry Andric       if (LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
480349cc55cSDimitry Andric         FoundBucket = ThisBucket;
481349cc55cSDimitry Andric         return true;
482349cc55cSDimitry Andric       }
483349cc55cSDimitry Andric 
484349cc55cSDimitry Andric       // If we found an empty bucket, the key doesn't exist in the set.
485349cc55cSDimitry Andric       // Insert it and return the default value.
486349cc55cSDimitry Andric       if (LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) {
487349cc55cSDimitry Andric         // If we've already seen a tombstone while probing, fill it in instead
488349cc55cSDimitry Andric         // of the empty bucket we eventually probed to.
489349cc55cSDimitry Andric         FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
490349cc55cSDimitry Andric         return false;
491349cc55cSDimitry Andric       }
492349cc55cSDimitry Andric 
493349cc55cSDimitry Andric       // If this is a tombstone, remember it.  If Val ends up not in the map, we
494349cc55cSDimitry Andric       // prefer to return it than something that would require more probing.
495349cc55cSDimitry Andric       if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) &&
496349cc55cSDimitry Andric           !FoundTombstone)
497349cc55cSDimitry Andric         FoundTombstone = ThisBucket;  // Remember the first tombstone found.
498349cc55cSDimitry Andric 
499349cc55cSDimitry Andric       // Otherwise, it's a hash collision or a tombstone, continue quadratic
500349cc55cSDimitry Andric       // probing.
501349cc55cSDimitry Andric       BucketNo += ProbeAmt++;
502349cc55cSDimitry Andric       BucketNo &= (NumBuckets - 1);
503349cc55cSDimitry Andric     }
504349cc55cSDimitry Andric   }
505349cc55cSDimitry Andric 
506349cc55cSDimitry Andric   template <typename LookupKeyT>
LookupBucketFor(const LookupKeyT & Val,BucketT * & FoundBucket)507349cc55cSDimitry Andric   bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) {
508349cc55cSDimitry Andric     const BucketT *ConstFoundBucket;
509349cc55cSDimitry Andric     bool Result = const_cast<const DenseMapBase *>(this)->LookupBucketFor(
510349cc55cSDimitry Andric         Val, ConstFoundBucket);
511349cc55cSDimitry Andric     FoundBucket = const_cast<BucketT *>(ConstFoundBucket);
512349cc55cSDimitry Andric     return Result;
513349cc55cSDimitry Andric   }
514349cc55cSDimitry Andric 
515349cc55cSDimitry Andric  public:
516349cc55cSDimitry Andric   /// Return the approximate size (in bytes) of the actual map.
517349cc55cSDimitry Andric   /// This is just the raw memory used by DenseMap.
518349cc55cSDimitry Andric   /// If entries are pointers to objects, the size of the referenced objects
519349cc55cSDimitry Andric   /// are not included.
getMemorySize()520349cc55cSDimitry Andric   uptr getMemorySize() const {
521349cc55cSDimitry Andric     return RoundUpTo(getNumBuckets() * sizeof(BucketT), GetPageSizeCached());
522349cc55cSDimitry Andric   }
523349cc55cSDimitry Andric };
524349cc55cSDimitry Andric 
525*4824e7fdSDimitry Andric /// Equality comparison for DenseMap.
526*4824e7fdSDimitry Andric ///
527*4824e7fdSDimitry Andric /// Iterates over elements of LHS confirming that each (key, value) pair in LHS
528*4824e7fdSDimitry Andric /// is also in RHS, and that no additional pairs are in RHS.
529*4824e7fdSDimitry Andric /// Equivalent to N calls to RHS.find and N value comparisons. Amortized
530*4824e7fdSDimitry Andric /// complexity is linear, worst case is O(N^2) (if every hash collides).
531*4824e7fdSDimitry Andric template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
532*4824e7fdSDimitry Andric           typename BucketT>
533*4824e7fdSDimitry Andric bool operator==(
534*4824e7fdSDimitry Andric     const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
535*4824e7fdSDimitry Andric     const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
536*4824e7fdSDimitry Andric   if (LHS.size() != RHS.size())
537*4824e7fdSDimitry Andric     return false;
538*4824e7fdSDimitry Andric 
539*4824e7fdSDimitry Andric   bool R = true;
540*4824e7fdSDimitry Andric   LHS.forEach(
541*4824e7fdSDimitry Andric       [&](const typename DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT,
542*4824e7fdSDimitry Andric                                       BucketT>::value_type &KV) -> bool {
543*4824e7fdSDimitry Andric         const auto *I = RHS.find(KV.first);
544*4824e7fdSDimitry Andric         if (!I || I->second != KV.second) {
545*4824e7fdSDimitry Andric           R = false;
546*4824e7fdSDimitry Andric           return false;
547*4824e7fdSDimitry Andric         }
548*4824e7fdSDimitry Andric         return true;
549*4824e7fdSDimitry Andric       });
550*4824e7fdSDimitry Andric 
551*4824e7fdSDimitry Andric   return R;
552*4824e7fdSDimitry Andric }
553*4824e7fdSDimitry Andric 
554349cc55cSDimitry Andric /// Inequality comparison for DenseMap.
555349cc55cSDimitry Andric ///
556349cc55cSDimitry Andric /// Equivalent to !(LHS == RHS). See operator== for performance notes.
557349cc55cSDimitry Andric template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
558349cc55cSDimitry Andric           typename BucketT>
559349cc55cSDimitry Andric bool operator!=(
560349cc55cSDimitry Andric     const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
561349cc55cSDimitry Andric     const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
562349cc55cSDimitry Andric   return !(LHS == RHS);
563349cc55cSDimitry Andric }
564349cc55cSDimitry Andric 
565349cc55cSDimitry Andric template <typename KeyT, typename ValueT,
566349cc55cSDimitry Andric           typename KeyInfoT = DenseMapInfo<KeyT>,
567349cc55cSDimitry Andric           typename BucketT = detail::DenseMapPair<KeyT, ValueT>>
568349cc55cSDimitry Andric class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
569349cc55cSDimitry Andric                                      KeyT, ValueT, KeyInfoT, BucketT> {
570349cc55cSDimitry Andric   friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
571349cc55cSDimitry Andric 
572349cc55cSDimitry Andric   // Lift some types from the dependent base class into this class for
573349cc55cSDimitry Andric   // simplicity of referring to them.
574349cc55cSDimitry Andric   using BaseT = DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
575349cc55cSDimitry Andric 
576349cc55cSDimitry Andric   BucketT *Buckets = nullptr;
577349cc55cSDimitry Andric   unsigned NumEntries = 0;
578349cc55cSDimitry Andric   unsigned NumTombstones = 0;
579349cc55cSDimitry Andric   unsigned NumBuckets = 0;
580349cc55cSDimitry Andric 
581349cc55cSDimitry Andric  public:
582349cc55cSDimitry Andric   /// Create a DenseMap with an optional \p InitialReserve that guarantee that
583349cc55cSDimitry Andric   /// this number of elements can be inserted in the map without grow()
DenseMap(unsigned InitialReserve)584349cc55cSDimitry Andric   explicit DenseMap(unsigned InitialReserve) { init(InitialReserve); }
585349cc55cSDimitry Andric   constexpr DenseMap() = default;
586349cc55cSDimitry Andric 
DenseMap(const DenseMap & other)587349cc55cSDimitry Andric   DenseMap(const DenseMap &other) : BaseT() {
588349cc55cSDimitry Andric     init(0);
589349cc55cSDimitry Andric     copyFrom(other);
590349cc55cSDimitry Andric   }
591349cc55cSDimitry Andric 
DenseMap(DenseMap && other)592349cc55cSDimitry Andric   DenseMap(DenseMap &&other) : BaseT() {
593349cc55cSDimitry Andric     init(0);
594349cc55cSDimitry Andric     swap(other);
595349cc55cSDimitry Andric   }
596349cc55cSDimitry Andric 
~DenseMap()597349cc55cSDimitry Andric   ~DenseMap() {
598349cc55cSDimitry Andric     this->destroyAll();
599349cc55cSDimitry Andric     deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets);
600349cc55cSDimitry Andric   }
601349cc55cSDimitry Andric 
swap(DenseMap & RHS)602349cc55cSDimitry Andric   void swap(DenseMap &RHS) {
603349cc55cSDimitry Andric     Swap(Buckets, RHS.Buckets);
604349cc55cSDimitry Andric     Swap(NumEntries, RHS.NumEntries);
605349cc55cSDimitry Andric     Swap(NumTombstones, RHS.NumTombstones);
606349cc55cSDimitry Andric     Swap(NumBuckets, RHS.NumBuckets);
607349cc55cSDimitry Andric   }
608349cc55cSDimitry Andric 
609349cc55cSDimitry Andric   DenseMap &operator=(const DenseMap &other) {
610349cc55cSDimitry Andric     if (&other != this)
611349cc55cSDimitry Andric       copyFrom(other);
612349cc55cSDimitry Andric     return *this;
613349cc55cSDimitry Andric   }
614349cc55cSDimitry Andric 
615349cc55cSDimitry Andric   DenseMap &operator=(DenseMap &&other) {
616349cc55cSDimitry Andric     this->destroyAll();
617349cc55cSDimitry Andric     deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
618349cc55cSDimitry Andric     init(0);
619349cc55cSDimitry Andric     swap(other);
620349cc55cSDimitry Andric     return *this;
621349cc55cSDimitry Andric   }
622349cc55cSDimitry Andric 
copyFrom(const DenseMap & other)623349cc55cSDimitry Andric   void copyFrom(const DenseMap &other) {
624349cc55cSDimitry Andric     this->destroyAll();
625349cc55cSDimitry Andric     deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets);
626349cc55cSDimitry Andric     if (allocateBuckets(other.NumBuckets)) {
627349cc55cSDimitry Andric       this->BaseT::copyFrom(other);
628349cc55cSDimitry Andric     } else {
629349cc55cSDimitry Andric       NumEntries = 0;
630349cc55cSDimitry Andric       NumTombstones = 0;
631349cc55cSDimitry Andric     }
632349cc55cSDimitry Andric   }
633349cc55cSDimitry Andric 
init(unsigned InitNumEntries)634349cc55cSDimitry Andric   void init(unsigned InitNumEntries) {
635349cc55cSDimitry Andric     auto InitBuckets = BaseT::getMinBucketToReserveForEntries(InitNumEntries);
636349cc55cSDimitry Andric     if (allocateBuckets(InitBuckets)) {
637349cc55cSDimitry Andric       this->BaseT::initEmpty();
638349cc55cSDimitry Andric     } else {
639349cc55cSDimitry Andric       NumEntries = 0;
640349cc55cSDimitry Andric       NumTombstones = 0;
641349cc55cSDimitry Andric     }
642349cc55cSDimitry Andric   }
643349cc55cSDimitry Andric 
grow(unsigned AtLeast)644349cc55cSDimitry Andric   void grow(unsigned AtLeast) {
645349cc55cSDimitry Andric     unsigned OldNumBuckets = NumBuckets;
646349cc55cSDimitry Andric     BucketT *OldBuckets = Buckets;
647349cc55cSDimitry Andric 
648349cc55cSDimitry Andric     allocateBuckets(RoundUpToPowerOfTwo(Max<unsigned>(64, AtLeast)));
649349cc55cSDimitry Andric     CHECK(Buckets);
650349cc55cSDimitry Andric     if (!OldBuckets) {
651349cc55cSDimitry Andric       this->BaseT::initEmpty();
652349cc55cSDimitry Andric       return;
653349cc55cSDimitry Andric     }
654349cc55cSDimitry Andric 
655349cc55cSDimitry Andric     this->moveFromOldBuckets(OldBuckets, OldBuckets + OldNumBuckets);
656349cc55cSDimitry Andric 
657349cc55cSDimitry Andric     // Free the old table.
658349cc55cSDimitry Andric     deallocate_buffer(OldBuckets, sizeof(BucketT) * OldNumBuckets);
659349cc55cSDimitry Andric   }
660349cc55cSDimitry Andric 
661349cc55cSDimitry Andric  private:
getNumEntries()662349cc55cSDimitry Andric   unsigned getNumEntries() const { return NumEntries; }
663349cc55cSDimitry Andric 
setNumEntries(unsigned Num)664349cc55cSDimitry Andric   void setNumEntries(unsigned Num) { NumEntries = Num; }
665349cc55cSDimitry Andric 
getNumTombstones()666349cc55cSDimitry Andric   unsigned getNumTombstones() const { return NumTombstones; }
667349cc55cSDimitry Andric 
setNumTombstones(unsigned Num)668349cc55cSDimitry Andric   void setNumTombstones(unsigned Num) { NumTombstones = Num; }
669349cc55cSDimitry Andric 
getBuckets()670349cc55cSDimitry Andric   BucketT *getBuckets() const { return Buckets; }
671349cc55cSDimitry Andric 
getNumBuckets()672349cc55cSDimitry Andric   unsigned getNumBuckets() const { return NumBuckets; }
673349cc55cSDimitry Andric 
allocateBuckets(unsigned Num)674349cc55cSDimitry Andric   bool allocateBuckets(unsigned Num) {
675349cc55cSDimitry Andric     NumBuckets = Num;
676349cc55cSDimitry Andric     if (NumBuckets == 0) {
677349cc55cSDimitry Andric       Buckets = nullptr;
678349cc55cSDimitry Andric       return false;
679349cc55cSDimitry Andric     }
680349cc55cSDimitry Andric 
681349cc55cSDimitry Andric     uptr Size = sizeof(BucketT) * NumBuckets;
682349cc55cSDimitry Andric     if (Size * 2 <= GetPageSizeCached()) {
683349cc55cSDimitry Andric       // We always allocate at least a page, so use entire space.
684349cc55cSDimitry Andric       unsigned Log2 = MostSignificantSetBitIndex(GetPageSizeCached() / Size);
685349cc55cSDimitry Andric       Size <<= Log2;
686349cc55cSDimitry Andric       NumBuckets <<= Log2;
687349cc55cSDimitry Andric       CHECK_EQ(Size, sizeof(BucketT) * NumBuckets);
688349cc55cSDimitry Andric       CHECK_GT(Size * 2, GetPageSizeCached());
689349cc55cSDimitry Andric     }
690349cc55cSDimitry Andric     Buckets = static_cast<BucketT *>(allocate_buffer(Size));
691349cc55cSDimitry Andric     return true;
692349cc55cSDimitry Andric   }
693349cc55cSDimitry Andric 
allocate_buffer(uptr Size)694349cc55cSDimitry Andric   static void *allocate_buffer(uptr Size) {
695349cc55cSDimitry Andric     return MmapOrDie(RoundUpTo(Size, GetPageSizeCached()), "DenseMap");
696349cc55cSDimitry Andric   }
697349cc55cSDimitry Andric 
deallocate_buffer(void * Ptr,uptr Size)698349cc55cSDimitry Andric   static void deallocate_buffer(void *Ptr, uptr Size) {
699349cc55cSDimitry Andric     UnmapOrDie(Ptr, RoundUpTo(Size, GetPageSizeCached()));
700349cc55cSDimitry Andric   }
701349cc55cSDimitry Andric };
702349cc55cSDimitry Andric 
703349cc55cSDimitry Andric }  // namespace __sanitizer
704349cc55cSDimitry Andric 
705349cc55cSDimitry Andric #endif  // SANITIZER_DENSE_MAP_H
706