(root)/
gcc-13.2.0/
libsanitizer/
sanitizer_common/
sanitizer_dense_map.h
       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