xref: /openbsd-src/gnu/llvm/compiler-rt/lib/sanitizer_common/sanitizer_dense_map.h (revision 810390e339a5425391477d5d41c78d7cab2424ac)
1*810390e3Srobert //===- sanitizer_dense_map.h - Dense probed hash table ----------*- C++ -*-===//
2*810390e3Srobert //
3*810390e3Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*810390e3Srobert // See https://llvm.org/LICENSE.txt for license information.
5*810390e3Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*810390e3Srobert //
7*810390e3Srobert //===----------------------------------------------------------------------===//
8*810390e3Srobert //
9*810390e3Srobert // This is fork of llvm/ADT/DenseMap.h class with the following changes:
10*810390e3Srobert //  * Use mmap to allocate.
11*810390e3Srobert //  * No iterators.
12*810390e3Srobert //  * Does not shrink.
13*810390e3Srobert //
14*810390e3Srobert //===----------------------------------------------------------------------===//
15*810390e3Srobert 
16*810390e3Srobert #ifndef SANITIZER_DENSE_MAP_H
17*810390e3Srobert #define SANITIZER_DENSE_MAP_H
18*810390e3Srobert 
19*810390e3Srobert #include "sanitizer_common.h"
20*810390e3Srobert #include "sanitizer_dense_map_info.h"
21*810390e3Srobert #include "sanitizer_internal_defs.h"
22*810390e3Srobert #include "sanitizer_type_traits.h"
23*810390e3Srobert 
24*810390e3Srobert namespace __sanitizer {
25*810390e3Srobert 
26*810390e3Srobert template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
27*810390e3Srobert           typename BucketT>
28*810390e3Srobert class DenseMapBase {
29*810390e3Srobert  public:
30*810390e3Srobert   using size_type = unsigned;
31*810390e3Srobert   using key_type = KeyT;
32*810390e3Srobert   using mapped_type = ValueT;
33*810390e3Srobert   using value_type = BucketT;
34*810390e3Srobert 
empty()35*810390e3Srobert   WARN_UNUSED_RESULT bool empty() const { return getNumEntries() == 0; }
size()36*810390e3Srobert   unsigned size() const { return getNumEntries(); }
37*810390e3Srobert 
38*810390e3Srobert   /// Grow the densemap so that it can contain at least \p NumEntries items
39*810390e3Srobert   /// before resizing again.
reserve(size_type NumEntries)40*810390e3Srobert   void reserve(size_type NumEntries) {
41*810390e3Srobert     auto NumBuckets = getMinBucketToReserveForEntries(NumEntries);
42*810390e3Srobert     if (NumBuckets > getNumBuckets())
43*810390e3Srobert       grow(NumBuckets);
44*810390e3Srobert   }
45*810390e3Srobert 
clear()46*810390e3Srobert   void clear() {
47*810390e3Srobert     if (getNumEntries() == 0 && getNumTombstones() == 0)
48*810390e3Srobert       return;
49*810390e3Srobert 
50*810390e3Srobert     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
51*810390e3Srobert     if (__sanitizer::is_trivially_destructible<ValueT>::value) {
52*810390e3Srobert       // Use a simpler loop when values don't need destruction.
53*810390e3Srobert       for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
54*810390e3Srobert         P->getFirst() = EmptyKey;
55*810390e3Srobert     } else {
56*810390e3Srobert       unsigned NumEntries = getNumEntries();
57*810390e3Srobert       for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
58*810390e3Srobert         if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
59*810390e3Srobert           if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
60*810390e3Srobert             P->getSecond().~ValueT();
61*810390e3Srobert             --NumEntries;
62*810390e3Srobert           }
63*810390e3Srobert           P->getFirst() = EmptyKey;
64*810390e3Srobert         }
65*810390e3Srobert       }
66*810390e3Srobert       CHECK_EQ(NumEntries, 0);
67*810390e3Srobert     }
68*810390e3Srobert     setNumEntries(0);
69*810390e3Srobert     setNumTombstones(0);
70*810390e3Srobert   }
71*810390e3Srobert 
72*810390e3Srobert   /// Return 1 if the specified key is in the map, 0 otherwise.
count(const KeyT & Key)73*810390e3Srobert   size_type count(const KeyT &Key) const {
74*810390e3Srobert     const BucketT *TheBucket;
75*810390e3Srobert     return LookupBucketFor(Key, TheBucket) ? 1 : 0;
76*810390e3Srobert   }
77*810390e3Srobert 
find(const KeyT & Key)78*810390e3Srobert   value_type *find(const KeyT &Key) {
79*810390e3Srobert     BucketT *TheBucket;
80*810390e3Srobert     if (LookupBucketFor(Key, TheBucket))
81*810390e3Srobert       return TheBucket;
82*810390e3Srobert     return nullptr;
83*810390e3Srobert   }
find(const KeyT & Key)84*810390e3Srobert   const value_type *find(const KeyT &Key) const {
85*810390e3Srobert     const BucketT *TheBucket;
86*810390e3Srobert     if (LookupBucketFor(Key, TheBucket))
87*810390e3Srobert       return TheBucket;
88*810390e3Srobert     return nullptr;
89*810390e3Srobert   }
90*810390e3Srobert 
91*810390e3Srobert   /// Alternate version of find() which allows a different, and possibly
92*810390e3Srobert   /// less expensive, key type.
93*810390e3Srobert   /// The DenseMapInfo is responsible for supplying methods
94*810390e3Srobert   /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key
95*810390e3Srobert   /// type used.
96*810390e3Srobert   template <class LookupKeyT>
find_as(const LookupKeyT & Key)97*810390e3Srobert   value_type *find_as(const LookupKeyT &Key) {
98*810390e3Srobert     BucketT *TheBucket;
99*810390e3Srobert     if (LookupBucketFor(Key, TheBucket))
100*810390e3Srobert       return TheBucket;
101*810390e3Srobert     return nullptr;
102*810390e3Srobert   }
103*810390e3Srobert   template <class LookupKeyT>
find_as(const LookupKeyT & Key)104*810390e3Srobert   const value_type *find_as(const LookupKeyT &Key) const {
105*810390e3Srobert     const BucketT *TheBucket;
106*810390e3Srobert     if (LookupBucketFor(Key, TheBucket))
107*810390e3Srobert       return TheBucket;
108*810390e3Srobert     return nullptr;
109*810390e3Srobert   }
110*810390e3Srobert 
111*810390e3Srobert   /// lookup - Return the entry for the specified key, or a default
112*810390e3Srobert   /// constructed value if no such entry exists.
lookup(const KeyT & Key)113*810390e3Srobert   ValueT lookup(const KeyT &Key) const {
114*810390e3Srobert     const BucketT *TheBucket;
115*810390e3Srobert     if (LookupBucketFor(Key, TheBucket))
116*810390e3Srobert       return TheBucket->getSecond();
117*810390e3Srobert     return ValueT();
118*810390e3Srobert   }
119*810390e3Srobert 
120*810390e3Srobert   // Inserts key,value pair into the map if the key isn't already in the map.
121*810390e3Srobert   // If the key is already in the map, it returns false and doesn't update the
122*810390e3Srobert   // value.
insert(const value_type & KV)123*810390e3Srobert   detail::DenseMapPair<value_type *, bool> insert(const value_type &KV) {
124*810390e3Srobert     return try_emplace(KV.first, KV.second);
125*810390e3Srobert   }
126*810390e3Srobert 
127*810390e3Srobert   // Inserts key,value pair into the map if the key isn't already in the map.
128*810390e3Srobert   // If the key is already in the map, it returns false and doesn't update the
129*810390e3Srobert   // value.
insert(value_type && KV)130*810390e3Srobert   detail::DenseMapPair<value_type *, bool> insert(value_type &&KV) {
131*810390e3Srobert     return try_emplace(__sanitizer::move(KV.first),
132*810390e3Srobert                        __sanitizer::move(KV.second));
133*810390e3Srobert   }
134*810390e3Srobert 
135*810390e3Srobert   // Inserts key,value pair into the map if the key isn't already in the map.
136*810390e3Srobert   // The value is constructed in-place if the key is not in the map, otherwise
137*810390e3Srobert   // it is not moved.
138*810390e3Srobert   template <typename... Ts>
try_emplace(KeyT && Key,Ts &&...Args)139*810390e3Srobert   detail::DenseMapPair<value_type *, bool> try_emplace(KeyT &&Key,
140*810390e3Srobert                                                        Ts &&...Args) {
141*810390e3Srobert     BucketT *TheBucket;
142*810390e3Srobert     if (LookupBucketFor(Key, TheBucket))
143*810390e3Srobert       return {TheBucket, false};  // Already in map.
144*810390e3Srobert 
145*810390e3Srobert     // Otherwise, insert the new element.
146*810390e3Srobert     TheBucket = InsertIntoBucket(TheBucket, __sanitizer::move(Key),
147*810390e3Srobert                                  __sanitizer::forward<Ts>(Args)...);
148*810390e3Srobert     return {TheBucket, true};
149*810390e3Srobert   }
150*810390e3Srobert 
151*810390e3Srobert   // Inserts key,value pair into the map if the key isn't already in the map.
152*810390e3Srobert   // The value is constructed in-place if the key is not in the map, otherwise
153*810390e3Srobert   // it is not moved.
154*810390e3Srobert   template <typename... Ts>
try_emplace(const KeyT & Key,Ts &&...Args)155*810390e3Srobert   detail::DenseMapPair<value_type *, bool> try_emplace(const KeyT &Key,
156*810390e3Srobert                                                        Ts &&...Args) {
157*810390e3Srobert     BucketT *TheBucket;
158*810390e3Srobert     if (LookupBucketFor(Key, TheBucket))
159*810390e3Srobert       return {TheBucket, false};  // Already in map.
160*810390e3Srobert 
161*810390e3Srobert     // Otherwise, insert the new element.
162*810390e3Srobert     TheBucket =
163*810390e3Srobert         InsertIntoBucket(TheBucket, Key, __sanitizer::forward<Ts>(Args)...);
164*810390e3Srobert     return {TheBucket, true};
165*810390e3Srobert   }
166*810390e3Srobert 
167*810390e3Srobert   /// Alternate version of insert() which allows a different, and possibly
168*810390e3Srobert   /// less expensive, key type.
169*810390e3Srobert   /// The DenseMapInfo is responsible for supplying methods
170*810390e3Srobert   /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key
171*810390e3Srobert   /// type used.
172*810390e3Srobert   template <typename LookupKeyT>
insert_as(value_type && KV,const LookupKeyT & Val)173*810390e3Srobert   detail::DenseMapPair<value_type *, bool> insert_as(value_type &&KV,
174*810390e3Srobert                                                      const LookupKeyT &Val) {
175*810390e3Srobert     BucketT *TheBucket;
176*810390e3Srobert     if (LookupBucketFor(Val, TheBucket))
177*810390e3Srobert       return {TheBucket, false};  // Already in map.
178*810390e3Srobert 
179*810390e3Srobert     // Otherwise, insert the new element.
180*810390e3Srobert     TheBucket =
181*810390e3Srobert         InsertIntoBucketWithLookup(TheBucket, __sanitizer::move(KV.first),
182*810390e3Srobert                                    __sanitizer::move(KV.second), Val);
183*810390e3Srobert     return {TheBucket, true};
184*810390e3Srobert   }
185*810390e3Srobert 
erase(const KeyT & Val)186*810390e3Srobert   bool erase(const KeyT &Val) {
187*810390e3Srobert     BucketT *TheBucket;
188*810390e3Srobert     if (!LookupBucketFor(Val, TheBucket))
189*810390e3Srobert       return false;  // not in map.
190*810390e3Srobert 
191*810390e3Srobert     TheBucket->getSecond().~ValueT();
192*810390e3Srobert     TheBucket->getFirst() = getTombstoneKey();
193*810390e3Srobert     decrementNumEntries();
194*810390e3Srobert     incrementNumTombstones();
195*810390e3Srobert     return true;
196*810390e3Srobert   }
197*810390e3Srobert 
erase(value_type * I)198*810390e3Srobert   void erase(value_type *I) {
199*810390e3Srobert     CHECK_NE(I, nullptr);
200*810390e3Srobert     BucketT *TheBucket = &*I;
201*810390e3Srobert     TheBucket->getSecond().~ValueT();
202*810390e3Srobert     TheBucket->getFirst() = getTombstoneKey();
203*810390e3Srobert     decrementNumEntries();
204*810390e3Srobert     incrementNumTombstones();
205*810390e3Srobert   }
206*810390e3Srobert 
FindAndConstruct(const KeyT & Key)207*810390e3Srobert   value_type &FindAndConstruct(const KeyT &Key) {
208*810390e3Srobert     BucketT *TheBucket;
209*810390e3Srobert     if (LookupBucketFor(Key, TheBucket))
210*810390e3Srobert       return *TheBucket;
211*810390e3Srobert 
212*810390e3Srobert     return *InsertIntoBucket(TheBucket, Key);
213*810390e3Srobert   }
214*810390e3Srobert 
215*810390e3Srobert   ValueT &operator[](const KeyT &Key) { return FindAndConstruct(Key).second; }
216*810390e3Srobert 
FindAndConstruct(KeyT && Key)217*810390e3Srobert   value_type &FindAndConstruct(KeyT &&Key) {
218*810390e3Srobert     BucketT *TheBucket;
219*810390e3Srobert     if (LookupBucketFor(Key, TheBucket))
220*810390e3Srobert       return *TheBucket;
221*810390e3Srobert 
222*810390e3Srobert     return *InsertIntoBucket(TheBucket, __sanitizer::move(Key));
223*810390e3Srobert   }
224*810390e3Srobert 
225*810390e3Srobert   ValueT &operator[](KeyT &&Key) {
226*810390e3Srobert     return FindAndConstruct(__sanitizer::move(Key)).second;
227*810390e3Srobert   }
228*810390e3Srobert 
229*810390e3Srobert   /// Iterate over active entries of the container.
230*810390e3Srobert   ///
231*810390e3Srobert   /// Function can return fast to stop the process.
232*810390e3Srobert   template <class Fn>
forEach(Fn fn)233*810390e3Srobert   void forEach(Fn fn) {
234*810390e3Srobert     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
235*810390e3Srobert     for (auto *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
236*810390e3Srobert       const KeyT K = P->getFirst();
237*810390e3Srobert       if (!KeyInfoT::isEqual(K, EmptyKey) &&
238*810390e3Srobert           !KeyInfoT::isEqual(K, TombstoneKey)) {
239*810390e3Srobert         if (!fn(*P))
240*810390e3Srobert           return;
241*810390e3Srobert       }
242*810390e3Srobert     }
243*810390e3Srobert   }
244*810390e3Srobert 
245*810390e3Srobert   template <class Fn>
forEach(Fn fn)246*810390e3Srobert   void forEach(Fn fn) const {
247*810390e3Srobert     const_cast<DenseMapBase *>(this)->forEach(
248*810390e3Srobert         [&](const value_type &KV) { return fn(KV); });
249*810390e3Srobert   }
250*810390e3Srobert 
251*810390e3Srobert  protected:
252*810390e3Srobert   DenseMapBase() = default;
253*810390e3Srobert 
destroyAll()254*810390e3Srobert   void destroyAll() {
255*810390e3Srobert     if (getNumBuckets() == 0)  // Nothing to do.
256*810390e3Srobert       return;
257*810390e3Srobert 
258*810390e3Srobert     const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
259*810390e3Srobert     for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
260*810390e3Srobert       if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) &&
261*810390e3Srobert           !KeyInfoT::isEqual(P->getFirst(), TombstoneKey))
262*810390e3Srobert         P->getSecond().~ValueT();
263*810390e3Srobert       P->getFirst().~KeyT();
264*810390e3Srobert     }
265*810390e3Srobert   }
266*810390e3Srobert 
initEmpty()267*810390e3Srobert   void initEmpty() {
268*810390e3Srobert     setNumEntries(0);
269*810390e3Srobert     setNumTombstones(0);
270*810390e3Srobert 
271*810390e3Srobert     CHECK_EQ((getNumBuckets() & (getNumBuckets() - 1)), 0);
272*810390e3Srobert     const KeyT EmptyKey = getEmptyKey();
273*810390e3Srobert     for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B)
274*810390e3Srobert       ::new (&B->getFirst()) KeyT(EmptyKey);
275*810390e3Srobert   }
276*810390e3Srobert 
277*810390e3Srobert   /// Returns the number of buckets to allocate to ensure that the DenseMap can
278*810390e3Srobert   /// accommodate \p NumEntries without need to grow().
getMinBucketToReserveForEntries(unsigned NumEntries)279*810390e3Srobert   unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
280*810390e3Srobert     // Ensure that "NumEntries * 4 < NumBuckets * 3"
281*810390e3Srobert     if (NumEntries == 0)
282*810390e3Srobert       return 0;
283*810390e3Srobert     // +1 is required because of the strict equality.
284*810390e3Srobert     // For example if NumEntries is 48, we need to return 401.
285*810390e3Srobert     return RoundUpToPowerOfTwo((NumEntries * 4 / 3 + 1) + /* NextPowerOf2 */ 1);
286*810390e3Srobert   }
287*810390e3Srobert 
moveFromOldBuckets(BucketT * OldBucketsBegin,BucketT * OldBucketsEnd)288*810390e3Srobert   void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) {
289*810390e3Srobert     initEmpty();
290*810390e3Srobert 
291*810390e3Srobert     // Insert all the old elements.
292*810390e3Srobert     const KeyT EmptyKey = getEmptyKey();
293*810390e3Srobert     const KeyT TombstoneKey = getTombstoneKey();
294*810390e3Srobert     for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) {
295*810390e3Srobert       if (!KeyInfoT::isEqual(B->getFirst(), EmptyKey) &&
296*810390e3Srobert           !KeyInfoT::isEqual(B->getFirst(), TombstoneKey)) {
297*810390e3Srobert         // Insert the key/value into the new table.
298*810390e3Srobert         BucketT *DestBucket;
299*810390e3Srobert         bool FoundVal = LookupBucketFor(B->getFirst(), DestBucket);
300*810390e3Srobert         (void)FoundVal;  // silence warning.
301*810390e3Srobert         CHECK(!FoundVal);
302*810390e3Srobert         DestBucket->getFirst() = __sanitizer::move(B->getFirst());
303*810390e3Srobert         ::new (&DestBucket->getSecond())
304*810390e3Srobert             ValueT(__sanitizer::move(B->getSecond()));
305*810390e3Srobert         incrementNumEntries();
306*810390e3Srobert 
307*810390e3Srobert         // Free the value.
308*810390e3Srobert         B->getSecond().~ValueT();
309*810390e3Srobert       }
310*810390e3Srobert       B->getFirst().~KeyT();
311*810390e3Srobert     }
312*810390e3Srobert   }
313*810390e3Srobert 
314*810390e3Srobert   template <typename OtherBaseT>
copyFrom(const DenseMapBase<OtherBaseT,KeyT,ValueT,KeyInfoT,BucketT> & other)315*810390e3Srobert   void copyFrom(
316*810390e3Srobert       const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT, BucketT> &other) {
317*810390e3Srobert     CHECK_NE(&other, this);
318*810390e3Srobert     CHECK_EQ(getNumBuckets(), other.getNumBuckets());
319*810390e3Srobert 
320*810390e3Srobert     setNumEntries(other.getNumEntries());
321*810390e3Srobert     setNumTombstones(other.getNumTombstones());
322*810390e3Srobert 
323*810390e3Srobert     if (__sanitizer::is_trivially_copyable<KeyT>::value &&
324*810390e3Srobert         __sanitizer::is_trivially_copyable<ValueT>::value)
325*810390e3Srobert       internal_memcpy(reinterpret_cast<void *>(getBuckets()),
326*810390e3Srobert                       other.getBuckets(), getNumBuckets() * sizeof(BucketT));
327*810390e3Srobert     else
328*810390e3Srobert       for (uptr i = 0; i < getNumBuckets(); ++i) {
329*810390e3Srobert         ::new (&getBuckets()[i].getFirst())
330*810390e3Srobert             KeyT(other.getBuckets()[i].getFirst());
331*810390e3Srobert         if (!KeyInfoT::isEqual(getBuckets()[i].getFirst(), getEmptyKey()) &&
332*810390e3Srobert             !KeyInfoT::isEqual(getBuckets()[i].getFirst(), getTombstoneKey()))
333*810390e3Srobert           ::new (&getBuckets()[i].getSecond())
334*810390e3Srobert               ValueT(other.getBuckets()[i].getSecond());
335*810390e3Srobert       }
336*810390e3Srobert   }
337*810390e3Srobert 
getHashValue(const KeyT & Val)338*810390e3Srobert   static unsigned getHashValue(const KeyT &Val) {
339*810390e3Srobert     return KeyInfoT::getHashValue(Val);
340*810390e3Srobert   }
341*810390e3Srobert 
342*810390e3Srobert   template <typename LookupKeyT>
getHashValue(const LookupKeyT & Val)343*810390e3Srobert   static unsigned getHashValue(const LookupKeyT &Val) {
344*810390e3Srobert     return KeyInfoT::getHashValue(Val);
345*810390e3Srobert   }
346*810390e3Srobert 
getEmptyKey()347*810390e3Srobert   static const KeyT getEmptyKey() { return KeyInfoT::getEmptyKey(); }
348*810390e3Srobert 
getTombstoneKey()349*810390e3Srobert   static const KeyT getTombstoneKey() { return KeyInfoT::getTombstoneKey(); }
350*810390e3Srobert 
351*810390e3Srobert  private:
getNumEntries()352*810390e3Srobert   unsigned getNumEntries() const {
353*810390e3Srobert     return static_cast<const DerivedT *>(this)->getNumEntries();
354*810390e3Srobert   }
355*810390e3Srobert 
setNumEntries(unsigned Num)356*810390e3Srobert   void setNumEntries(unsigned Num) {
357*810390e3Srobert     static_cast<DerivedT *>(this)->setNumEntries(Num);
358*810390e3Srobert   }
359*810390e3Srobert 
incrementNumEntries()360*810390e3Srobert   void incrementNumEntries() { setNumEntries(getNumEntries() + 1); }
361*810390e3Srobert 
decrementNumEntries()362*810390e3Srobert   void decrementNumEntries() { setNumEntries(getNumEntries() - 1); }
363*810390e3Srobert 
getNumTombstones()364*810390e3Srobert   unsigned getNumTombstones() const {
365*810390e3Srobert     return static_cast<const DerivedT *>(this)->getNumTombstones();
366*810390e3Srobert   }
367*810390e3Srobert 
setNumTombstones(unsigned Num)368*810390e3Srobert   void setNumTombstones(unsigned Num) {
369*810390e3Srobert     static_cast<DerivedT *>(this)->setNumTombstones(Num);
370*810390e3Srobert   }
371*810390e3Srobert 
incrementNumTombstones()372*810390e3Srobert   void incrementNumTombstones() { setNumTombstones(getNumTombstones() + 1); }
373*810390e3Srobert 
decrementNumTombstones()374*810390e3Srobert   void decrementNumTombstones() { setNumTombstones(getNumTombstones() - 1); }
375*810390e3Srobert 
getBuckets()376*810390e3Srobert   const BucketT *getBuckets() const {
377*810390e3Srobert     return static_cast<const DerivedT *>(this)->getBuckets();
378*810390e3Srobert   }
379*810390e3Srobert 
getBuckets()380*810390e3Srobert   BucketT *getBuckets() { return static_cast<DerivedT *>(this)->getBuckets(); }
381*810390e3Srobert 
getNumBuckets()382*810390e3Srobert   unsigned getNumBuckets() const {
383*810390e3Srobert     return static_cast<const DerivedT *>(this)->getNumBuckets();
384*810390e3Srobert   }
385*810390e3Srobert 
getBucketsEnd()386*810390e3Srobert   BucketT *getBucketsEnd() { return getBuckets() + getNumBuckets(); }
387*810390e3Srobert 
getBucketsEnd()388*810390e3Srobert   const BucketT *getBucketsEnd() const {
389*810390e3Srobert     return getBuckets() + getNumBuckets();
390*810390e3Srobert   }
391*810390e3Srobert 
grow(unsigned AtLeast)392*810390e3Srobert   void grow(unsigned AtLeast) { static_cast<DerivedT *>(this)->grow(AtLeast); }
393*810390e3Srobert 
394*810390e3Srobert   template <typename KeyArg, typename... ValueArgs>
InsertIntoBucket(BucketT * TheBucket,KeyArg && Key,ValueArgs &&...Values)395*810390e3Srobert   BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
396*810390e3Srobert                             ValueArgs &&...Values) {
397*810390e3Srobert     TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
398*810390e3Srobert 
399*810390e3Srobert     TheBucket->getFirst() = __sanitizer::forward<KeyArg>(Key);
400*810390e3Srobert     ::new (&TheBucket->getSecond())
401*810390e3Srobert         ValueT(__sanitizer::forward<ValueArgs>(Values)...);
402*810390e3Srobert     return TheBucket;
403*810390e3Srobert   }
404*810390e3Srobert 
405*810390e3Srobert   template <typename LookupKeyT>
InsertIntoBucketWithLookup(BucketT * TheBucket,KeyT && Key,ValueT && Value,LookupKeyT & Lookup)406*810390e3Srobert   BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key,
407*810390e3Srobert                                       ValueT &&Value, LookupKeyT &Lookup) {
408*810390e3Srobert     TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);
409*810390e3Srobert 
410*810390e3Srobert     TheBucket->getFirst() = __sanitizer::move(Key);
411*810390e3Srobert     ::new (&TheBucket->getSecond()) ValueT(__sanitizer::move(Value));
412*810390e3Srobert     return TheBucket;
413*810390e3Srobert   }
414*810390e3Srobert 
415*810390e3Srobert   template <typename LookupKeyT>
InsertIntoBucketImpl(const KeyT & Key,const LookupKeyT & Lookup,BucketT * TheBucket)416*810390e3Srobert   BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup,
417*810390e3Srobert                                 BucketT *TheBucket) {
418*810390e3Srobert     // If the load of the hash table is more than 3/4, or if fewer than 1/8 of
419*810390e3Srobert     // the buckets are empty (meaning that many are filled with tombstones),
420*810390e3Srobert     // grow the table.
421*810390e3Srobert     //
422*810390e3Srobert     // The later case is tricky.  For example, if we had one empty bucket with
423*810390e3Srobert     // tons of tombstones, failing lookups (e.g. for insertion) would have to
424*810390e3Srobert     // probe almost the entire table until it found the empty bucket.  If the
425*810390e3Srobert     // table completely filled with tombstones, no lookup would ever succeed,
426*810390e3Srobert     // causing infinite loops in lookup.
427*810390e3Srobert     unsigned NewNumEntries = getNumEntries() + 1;
428*810390e3Srobert     unsigned NumBuckets = getNumBuckets();
429*810390e3Srobert     if (UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) {
430*810390e3Srobert       this->grow(NumBuckets * 2);
431*810390e3Srobert       LookupBucketFor(Lookup, TheBucket);
432*810390e3Srobert       NumBuckets = getNumBuckets();
433*810390e3Srobert     } else if (UNLIKELY(NumBuckets - (NewNumEntries + getNumTombstones()) <=
434*810390e3Srobert                         NumBuckets / 8)) {
435*810390e3Srobert       this->grow(NumBuckets);
436*810390e3Srobert       LookupBucketFor(Lookup, TheBucket);
437*810390e3Srobert     }
438*810390e3Srobert     CHECK(TheBucket);
439*810390e3Srobert 
440*810390e3Srobert     // Only update the state after we've grown our bucket space appropriately
441*810390e3Srobert     // so that when growing buckets we have self-consistent entry count.
442*810390e3Srobert     incrementNumEntries();
443*810390e3Srobert 
444*810390e3Srobert     // If we are writing over a tombstone, remember this.
445*810390e3Srobert     const KeyT EmptyKey = getEmptyKey();
446*810390e3Srobert     if (!KeyInfoT::isEqual(TheBucket->getFirst(), EmptyKey))
447*810390e3Srobert       decrementNumTombstones();
448*810390e3Srobert 
449*810390e3Srobert     return TheBucket;
450*810390e3Srobert   }
451*810390e3Srobert 
452*810390e3Srobert   /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in
453*810390e3Srobert   /// FoundBucket.  If the bucket contains the key and a value, this returns
454*810390e3Srobert   /// true, otherwise it returns a bucket with an empty marker or tombstone and
455*810390e3Srobert   /// returns false.
456*810390e3Srobert   template <typename LookupKeyT>
LookupBucketFor(const LookupKeyT & Val,const BucketT * & FoundBucket)457*810390e3Srobert   bool LookupBucketFor(const LookupKeyT &Val,
458*810390e3Srobert                        const BucketT *&FoundBucket) const {
459*810390e3Srobert     const BucketT *BucketsPtr = getBuckets();
460*810390e3Srobert     const unsigned NumBuckets = getNumBuckets();
461*810390e3Srobert 
462*810390e3Srobert     if (NumBuckets == 0) {
463*810390e3Srobert       FoundBucket = nullptr;
464*810390e3Srobert       return false;
465*810390e3Srobert     }
466*810390e3Srobert 
467*810390e3Srobert     // FoundTombstone - Keep track of whether we find a tombstone while probing.
468*810390e3Srobert     const BucketT *FoundTombstone = nullptr;
469*810390e3Srobert     const KeyT EmptyKey = getEmptyKey();
470*810390e3Srobert     const KeyT TombstoneKey = getTombstoneKey();
471*810390e3Srobert     CHECK(!KeyInfoT::isEqual(Val, EmptyKey));
472*810390e3Srobert     CHECK(!KeyInfoT::isEqual(Val, TombstoneKey));
473*810390e3Srobert 
474*810390e3Srobert     unsigned BucketNo = getHashValue(Val) & (NumBuckets - 1);
475*810390e3Srobert     unsigned ProbeAmt = 1;
476*810390e3Srobert     while (true) {
477*810390e3Srobert       const BucketT *ThisBucket = BucketsPtr + BucketNo;
478*810390e3Srobert       // Found Val's bucket?  If so, return it.
479*810390e3Srobert       if (LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
480*810390e3Srobert         FoundBucket = ThisBucket;
481*810390e3Srobert         return true;
482*810390e3Srobert       }
483*810390e3Srobert 
484*810390e3Srobert       // If we found an empty bucket, the key doesn't exist in the set.
485*810390e3Srobert       // Insert it and return the default value.
486*810390e3Srobert       if (LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) {
487*810390e3Srobert         // If we've already seen a tombstone while probing, fill it in instead
488*810390e3Srobert         // of the empty bucket we eventually probed to.
489*810390e3Srobert         FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
490*810390e3Srobert         return false;
491*810390e3Srobert       }
492*810390e3Srobert 
493*810390e3Srobert       // If this is a tombstone, remember it.  If Val ends up not in the map, we
494*810390e3Srobert       // prefer to return it than something that would require more probing.
495*810390e3Srobert       if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) &&
496*810390e3Srobert           !FoundTombstone)
497*810390e3Srobert         FoundTombstone = ThisBucket;  // Remember the first tombstone found.
498*810390e3Srobert 
499*810390e3Srobert       // Otherwise, it's a hash collision or a tombstone, continue quadratic
500*810390e3Srobert       // probing.
501*810390e3Srobert       BucketNo += ProbeAmt++;
502*810390e3Srobert       BucketNo &= (NumBuckets - 1);
503*810390e3Srobert     }
504*810390e3Srobert   }
505*810390e3Srobert 
506*810390e3Srobert   template <typename LookupKeyT>
LookupBucketFor(const LookupKeyT & Val,BucketT * & FoundBucket)507*810390e3Srobert   bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) {
508*810390e3Srobert     const BucketT *ConstFoundBucket;
509*810390e3Srobert     bool Result = const_cast<const DenseMapBase *>(this)->LookupBucketFor(
510*810390e3Srobert         Val, ConstFoundBucket);
511*810390e3Srobert     FoundBucket = const_cast<BucketT *>(ConstFoundBucket);
512*810390e3Srobert     return Result;
513*810390e3Srobert   }
514*810390e3Srobert 
515*810390e3Srobert  public:
516*810390e3Srobert   /// Return the approximate size (in bytes) of the actual map.
517*810390e3Srobert   /// This is just the raw memory used by DenseMap.
518*810390e3Srobert   /// If entries are pointers to objects, the size of the referenced objects
519*810390e3Srobert   /// are not included.
getMemorySize()520*810390e3Srobert   uptr getMemorySize() const {
521*810390e3Srobert     return RoundUpTo(getNumBuckets() * sizeof(BucketT), GetPageSizeCached());
522*810390e3Srobert   }
523*810390e3Srobert };
524*810390e3Srobert 
525*810390e3Srobert /// Equality comparison for DenseMap.
526*810390e3Srobert ///
527*810390e3Srobert /// Iterates over elements of LHS confirming that each (key, value) pair in LHS
528*810390e3Srobert /// is also in RHS, and that no additional pairs are in RHS.
529*810390e3Srobert /// Equivalent to N calls to RHS.find and N value comparisons. Amortized
530*810390e3Srobert /// complexity is linear, worst case is O(N^2) (if every hash collides).
531*810390e3Srobert template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
532*810390e3Srobert           typename BucketT>
533*810390e3Srobert bool operator==(
534*810390e3Srobert     const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
535*810390e3Srobert     const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
536*810390e3Srobert   if (LHS.size() != RHS.size())
537*810390e3Srobert     return false;
538*810390e3Srobert 
539*810390e3Srobert   bool R = true;
540*810390e3Srobert   LHS.forEach(
541*810390e3Srobert       [&](const typename DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT,
542*810390e3Srobert                                       BucketT>::value_type &KV) -> bool {
543*810390e3Srobert         const auto *I = RHS.find(KV.first);
544*810390e3Srobert         if (!I || I->second != KV.second) {
545*810390e3Srobert           R = false;
546*810390e3Srobert           return false;
547*810390e3Srobert         }
548*810390e3Srobert         return true;
549*810390e3Srobert       });
550*810390e3Srobert 
551*810390e3Srobert   return R;
552*810390e3Srobert }
553*810390e3Srobert 
554*810390e3Srobert /// Inequality comparison for DenseMap.
555*810390e3Srobert ///
556*810390e3Srobert /// Equivalent to !(LHS == RHS). See operator== for performance notes.
557*810390e3Srobert template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
558*810390e3Srobert           typename BucketT>
559*810390e3Srobert bool operator!=(
560*810390e3Srobert     const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
561*810390e3Srobert     const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
562*810390e3Srobert   return !(LHS == RHS);
563*810390e3Srobert }
564*810390e3Srobert 
565*810390e3Srobert template <typename KeyT, typename ValueT,
566*810390e3Srobert           typename KeyInfoT = DenseMapInfo<KeyT>,
567*810390e3Srobert           typename BucketT = detail::DenseMapPair<KeyT, ValueT>>
568*810390e3Srobert class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
569*810390e3Srobert                                      KeyT, ValueT, KeyInfoT, BucketT> {
570*810390e3Srobert   friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
571*810390e3Srobert 
572*810390e3Srobert   // Lift some types from the dependent base class into this class for
573*810390e3Srobert   // simplicity of referring to them.
574*810390e3Srobert   using BaseT = DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
575*810390e3Srobert 
576*810390e3Srobert   BucketT *Buckets = nullptr;
577*810390e3Srobert   unsigned NumEntries = 0;
578*810390e3Srobert   unsigned NumTombstones = 0;
579*810390e3Srobert   unsigned NumBuckets = 0;
580*810390e3Srobert 
581*810390e3Srobert  public:
582*810390e3Srobert   /// Create a DenseMap with an optional \p InitialReserve that guarantee that
583*810390e3Srobert   /// this number of elements can be inserted in the map without grow()
DenseMap(unsigned InitialReserve)584*810390e3Srobert   explicit DenseMap(unsigned InitialReserve) { init(InitialReserve); }
585*810390e3Srobert   constexpr DenseMap() = default;
586*810390e3Srobert 
DenseMap(const DenseMap & other)587*810390e3Srobert   DenseMap(const DenseMap &other) : BaseT() {
588*810390e3Srobert     init(0);
589*810390e3Srobert     copyFrom(other);
590*810390e3Srobert   }
591*810390e3Srobert 
DenseMap(DenseMap && other)592*810390e3Srobert   DenseMap(DenseMap &&other) : BaseT() {
593*810390e3Srobert     init(0);
594*810390e3Srobert     swap(other);
595*810390e3Srobert   }
596*810390e3Srobert 
~DenseMap()597*810390e3Srobert   ~DenseMap() {
598*810390e3Srobert     this->destroyAll();
599*810390e3Srobert     deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets);
600*810390e3Srobert   }
601*810390e3Srobert 
swap(DenseMap & RHS)602*810390e3Srobert   void swap(DenseMap &RHS) {
603*810390e3Srobert     Swap(Buckets, RHS.Buckets);
604*810390e3Srobert     Swap(NumEntries, RHS.NumEntries);
605*810390e3Srobert     Swap(NumTombstones, RHS.NumTombstones);
606*810390e3Srobert     Swap(NumBuckets, RHS.NumBuckets);
607*810390e3Srobert   }
608*810390e3Srobert 
609*810390e3Srobert   DenseMap &operator=(const DenseMap &other) {
610*810390e3Srobert     if (&other != this)
611*810390e3Srobert       copyFrom(other);
612*810390e3Srobert     return *this;
613*810390e3Srobert   }
614*810390e3Srobert 
615*810390e3Srobert   DenseMap &operator=(DenseMap &&other) {
616*810390e3Srobert     this->destroyAll();
617*810390e3Srobert     deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
618*810390e3Srobert     init(0);
619*810390e3Srobert     swap(other);
620*810390e3Srobert     return *this;
621*810390e3Srobert   }
622*810390e3Srobert 
copyFrom(const DenseMap & other)623*810390e3Srobert   void copyFrom(const DenseMap &other) {
624*810390e3Srobert     this->destroyAll();
625*810390e3Srobert     deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets);
626*810390e3Srobert     if (allocateBuckets(other.NumBuckets)) {
627*810390e3Srobert       this->BaseT::copyFrom(other);
628*810390e3Srobert     } else {
629*810390e3Srobert       NumEntries = 0;
630*810390e3Srobert       NumTombstones = 0;
631*810390e3Srobert     }
632*810390e3Srobert   }
633*810390e3Srobert 
init(unsigned InitNumEntries)634*810390e3Srobert   void init(unsigned InitNumEntries) {
635*810390e3Srobert     auto InitBuckets = BaseT::getMinBucketToReserveForEntries(InitNumEntries);
636*810390e3Srobert     if (allocateBuckets(InitBuckets)) {
637*810390e3Srobert       this->BaseT::initEmpty();
638*810390e3Srobert     } else {
639*810390e3Srobert       NumEntries = 0;
640*810390e3Srobert       NumTombstones = 0;
641*810390e3Srobert     }
642*810390e3Srobert   }
643*810390e3Srobert 
grow(unsigned AtLeast)644*810390e3Srobert   void grow(unsigned AtLeast) {
645*810390e3Srobert     unsigned OldNumBuckets = NumBuckets;
646*810390e3Srobert     BucketT *OldBuckets = Buckets;
647*810390e3Srobert 
648*810390e3Srobert     allocateBuckets(RoundUpToPowerOfTwo(Max<unsigned>(64, AtLeast)));
649*810390e3Srobert     CHECK(Buckets);
650*810390e3Srobert     if (!OldBuckets) {
651*810390e3Srobert       this->BaseT::initEmpty();
652*810390e3Srobert       return;
653*810390e3Srobert     }
654*810390e3Srobert 
655*810390e3Srobert     this->moveFromOldBuckets(OldBuckets, OldBuckets + OldNumBuckets);
656*810390e3Srobert 
657*810390e3Srobert     // Free the old table.
658*810390e3Srobert     deallocate_buffer(OldBuckets, sizeof(BucketT) * OldNumBuckets);
659*810390e3Srobert   }
660*810390e3Srobert 
661*810390e3Srobert  private:
getNumEntries()662*810390e3Srobert   unsigned getNumEntries() const { return NumEntries; }
663*810390e3Srobert 
setNumEntries(unsigned Num)664*810390e3Srobert   void setNumEntries(unsigned Num) { NumEntries = Num; }
665*810390e3Srobert 
getNumTombstones()666*810390e3Srobert   unsigned getNumTombstones() const { return NumTombstones; }
667*810390e3Srobert 
setNumTombstones(unsigned Num)668*810390e3Srobert   void setNumTombstones(unsigned Num) { NumTombstones = Num; }
669*810390e3Srobert 
getBuckets()670*810390e3Srobert   BucketT *getBuckets() const { return Buckets; }
671*810390e3Srobert 
getNumBuckets()672*810390e3Srobert   unsigned getNumBuckets() const { return NumBuckets; }
673*810390e3Srobert 
allocateBuckets(unsigned Num)674*810390e3Srobert   bool allocateBuckets(unsigned Num) {
675*810390e3Srobert     NumBuckets = Num;
676*810390e3Srobert     if (NumBuckets == 0) {
677*810390e3Srobert       Buckets = nullptr;
678*810390e3Srobert       return false;
679*810390e3Srobert     }
680*810390e3Srobert 
681*810390e3Srobert     uptr Size = sizeof(BucketT) * NumBuckets;
682*810390e3Srobert     if (Size * 2 <= GetPageSizeCached()) {
683*810390e3Srobert       // We always allocate at least a page, so use entire space.
684*810390e3Srobert       unsigned Log2 = MostSignificantSetBitIndex(GetPageSizeCached() / Size);
685*810390e3Srobert       Size <<= Log2;
686*810390e3Srobert       NumBuckets <<= Log2;
687*810390e3Srobert       CHECK_EQ(Size, sizeof(BucketT) * NumBuckets);
688*810390e3Srobert       CHECK_GT(Size * 2, GetPageSizeCached());
689*810390e3Srobert     }
690*810390e3Srobert     Buckets = static_cast<BucketT *>(allocate_buffer(Size));
691*810390e3Srobert     return true;
692*810390e3Srobert   }
693*810390e3Srobert 
allocate_buffer(uptr Size)694*810390e3Srobert   static void *allocate_buffer(uptr Size) {
695*810390e3Srobert     return MmapOrDie(RoundUpTo(Size, GetPageSizeCached()), "DenseMap");
696*810390e3Srobert   }
697*810390e3Srobert 
deallocate_buffer(void * Ptr,uptr Size)698*810390e3Srobert   static void deallocate_buffer(void *Ptr, uptr Size) {
699*810390e3Srobert     UnmapOrDie(Ptr, RoundUpTo(Size, GetPageSizeCached()));
700*810390e3Srobert   }
701*810390e3Srobert };
702*810390e3Srobert 
703*810390e3Srobert }  // namespace __sanitizer
704*810390e3Srobert 
705*810390e3Srobert #endif  // SANITIZER_DENSE_MAP_H
706