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