123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705 |
- //===- sanitizer_dense_map.h - Dense probed hash table ----------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This is fork of llvm/ADT/DenseMap.h class with the following changes:
- // * Use mmap to allocate.
- // * No iterators.
- // * Does not shrink.
- //
- //===----------------------------------------------------------------------===//
- #ifndef SANITIZER_DENSE_MAP_H
- #define SANITIZER_DENSE_MAP_H
- #include "sanitizer_common.h"
- #include "sanitizer_dense_map_info.h"
- #include "sanitizer_internal_defs.h"
- #include "sanitizer_type_traits.h"
- namespace __sanitizer {
- template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
- typename BucketT>
- class DenseMapBase {
- public:
- using size_type = unsigned;
- using key_type = KeyT;
- using mapped_type = ValueT;
- using value_type = BucketT;
- WARN_UNUSED_RESULT bool empty() const { return getNumEntries() == 0; }
- unsigned size() const { return getNumEntries(); }
- /// Grow the densemap so that it can contain at least \p NumEntries items
- /// before resizing again.
- void reserve(size_type NumEntries) {
- auto NumBuckets = getMinBucketToReserveForEntries(NumEntries);
- if (NumBuckets > getNumBuckets())
- grow(NumBuckets);
- }
- void clear() {
- if (getNumEntries() == 0 && getNumTombstones() == 0)
- return;
- const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
- if (__sanitizer::is_trivially_destructible<ValueT>::value) {
- // Use a simpler loop when values don't need destruction.
- for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
- P->getFirst() = EmptyKey;
- } else {
- unsigned NumEntries = getNumEntries();
- for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
- if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
- if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
- P->getSecond().~ValueT();
- --NumEntries;
- }
- P->getFirst() = EmptyKey;
- }
- }
- CHECK_EQ(NumEntries, 0);
- }
- setNumEntries(0);
- setNumTombstones(0);
- }
- /// Return 1 if the specified key is in the map, 0 otherwise.
- size_type count(const KeyT &Key) const {
- const BucketT *TheBucket;
- return LookupBucketFor(Key, TheBucket) ? 1 : 0;
- }
- value_type *find(const KeyT &Key) {
- BucketT *TheBucket;
- if (LookupBucketFor(Key, TheBucket))
- return TheBucket;
- return nullptr;
- }
- const value_type *find(const KeyT &Key) const {
- const BucketT *TheBucket;
- if (LookupBucketFor(Key, TheBucket))
- return TheBucket;
- return nullptr;
- }
- /// Alternate version of find() which allows a different, and possibly
- /// less expensive, key type.
- /// The DenseMapInfo is responsible for supplying methods
- /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key
- /// type used.
- template <class LookupKeyT>
- value_type *find_as(const LookupKeyT &Key) {
- BucketT *TheBucket;
- if (LookupBucketFor(Key, TheBucket))
- return TheBucket;
- return nullptr;
- }
- template <class LookupKeyT>
- const value_type *find_as(const LookupKeyT &Key) const {
- const BucketT *TheBucket;
- if (LookupBucketFor(Key, TheBucket))
- return TheBucket;
- return nullptr;
- }
- /// lookup - Return the entry for the specified key, or a default
- /// constructed value if no such entry exists.
- ValueT lookup(const KeyT &Key) const {
- const BucketT *TheBucket;
- if (LookupBucketFor(Key, TheBucket))
- return TheBucket->getSecond();
- return ValueT();
- }
- // Inserts key,value pair into the map if the key isn't already in the map.
- // If the key is already in the map, it returns false and doesn't update the
- // value.
- detail::DenseMapPair<value_type *, bool> insert(const value_type &KV) {
- return try_emplace(KV.first, KV.second);
- }
- // Inserts key,value pair into the map if the key isn't already in the map.
- // If the key is already in the map, it returns false and doesn't update the
- // value.
- detail::DenseMapPair<value_type *, bool> insert(value_type &&KV) {
- return try_emplace(__sanitizer::move(KV.first),
- __sanitizer::move(KV.second));
- }
- // Inserts key,value pair into the map if the key isn't already in the map.
- // The value is constructed in-place if the key is not in the map, otherwise
- // it is not moved.
- template <typename... Ts>
- detail::DenseMapPair<value_type *, bool> try_emplace(KeyT &&Key,
- Ts &&...Args) {
- BucketT *TheBucket;
- if (LookupBucketFor(Key, TheBucket))
- return {TheBucket, false}; // Already in map.
- // Otherwise, insert the new element.
- TheBucket = InsertIntoBucket(TheBucket, __sanitizer::move(Key),
- __sanitizer::forward<Ts>(Args)...);
- return {TheBucket, true};
- }
- // Inserts key,value pair into the map if the key isn't already in the map.
- // The value is constructed in-place if the key is not in the map, otherwise
- // it is not moved.
- template <typename... Ts>
- detail::DenseMapPair<value_type *, bool> try_emplace(const KeyT &Key,
- Ts &&...Args) {
- BucketT *TheBucket;
- if (LookupBucketFor(Key, TheBucket))
- return {TheBucket, false}; // Already in map.
- // Otherwise, insert the new element.
- TheBucket =
- InsertIntoBucket(TheBucket, Key, __sanitizer::forward<Ts>(Args)...);
- return {TheBucket, true};
- }
- /// Alternate version of insert() which allows a different, and possibly
- /// less expensive, key type.
- /// The DenseMapInfo is responsible for supplying methods
- /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key
- /// type used.
- template <typename LookupKeyT>
- detail::DenseMapPair<value_type *, bool> insert_as(value_type &&KV,
- const LookupKeyT &Val) {
- BucketT *TheBucket;
- if (LookupBucketFor(Val, TheBucket))
- return {TheBucket, false}; // Already in map.
- // Otherwise, insert the new element.
- TheBucket =
- InsertIntoBucketWithLookup(TheBucket, __sanitizer::move(KV.first),
- __sanitizer::move(KV.second), Val);
- return {TheBucket, true};
- }
- bool erase(const KeyT &Val) {
- BucketT *TheBucket;
- if (!LookupBucketFor(Val, TheBucket))
- return false; // not in map.
- TheBucket->getSecond().~ValueT();
- TheBucket->getFirst() = getTombstoneKey();
- decrementNumEntries();
- incrementNumTombstones();
- return true;
- }
- void erase(value_type *I) {
- CHECK_NE(I, nullptr);
- BucketT *TheBucket = &*I;
- TheBucket->getSecond().~ValueT();
- TheBucket->getFirst() = getTombstoneKey();
- decrementNumEntries();
- incrementNumTombstones();
- }
- value_type &FindAndConstruct(const KeyT &Key) {
- BucketT *TheBucket;
- if (LookupBucketFor(Key, TheBucket))
- return *TheBucket;
- return *InsertIntoBucket(TheBucket, Key);
- }
- ValueT &operator[](const KeyT &Key) { return FindAndConstruct(Key).second; }
- value_type &FindAndConstruct(KeyT &&Key) {
- BucketT *TheBucket;
- if (LookupBucketFor(Key, TheBucket))
- return *TheBucket;
- return *InsertIntoBucket(TheBucket, __sanitizer::move(Key));
- }
- ValueT &operator[](KeyT &&Key) {
- return FindAndConstruct(__sanitizer::move(Key)).second;
- }
- /// Iterate over active entries of the container.
- ///
- /// Function can return fast to stop the process.
- template <class Fn>
- void forEach(Fn fn) {
- const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
- for (auto *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
- const KeyT K = P->getFirst();
- if (!KeyInfoT::isEqual(K, EmptyKey) &&
- !KeyInfoT::isEqual(K, TombstoneKey)) {
- if (!fn(*P))
- return;
- }
- }
- }
- template <class Fn>
- void forEach(Fn fn) const {
- const_cast<DenseMapBase *>(this)->forEach(
- [&](const value_type &KV) { return fn(KV); });
- }
- protected:
- DenseMapBase() = default;
- void destroyAll() {
- if (getNumBuckets() == 0) // Nothing to do.
- return;
- const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
- for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
- if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) &&
- !KeyInfoT::isEqual(P->getFirst(), TombstoneKey))
- P->getSecond().~ValueT();
- P->getFirst().~KeyT();
- }
- }
- void initEmpty() {
- setNumEntries(0);
- setNumTombstones(0);
- CHECK_EQ((getNumBuckets() & (getNumBuckets() - 1)), 0);
- const KeyT EmptyKey = getEmptyKey();
- for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B)
- ::new (&B->getFirst()) KeyT(EmptyKey);
- }
- /// Returns the number of buckets to allocate to ensure that the DenseMap can
- /// accommodate \p NumEntries without need to grow().
- unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
- // Ensure that "NumEntries * 4 < NumBuckets * 3"
- if (NumEntries == 0)
- return 0;
- // +1 is required because of the strict equality.
- // For example if NumEntries is 48, we need to return 401.
- return RoundUpToPowerOfTwo((NumEntries * 4 / 3 + 1) + /* NextPowerOf2 */ 1);
- }
- void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) {
- initEmpty();
- // Insert all the old elements.
- const KeyT EmptyKey = getEmptyKey();
- const KeyT TombstoneKey = getTombstoneKey();
- for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) {
- if (!KeyInfoT::isEqual(B->getFirst(), EmptyKey) &&
- !KeyInfoT::isEqual(B->getFirst(), TombstoneKey)) {
- // Insert the key/value into the new table.
- BucketT *DestBucket;
- bool FoundVal = LookupBucketFor(B->getFirst(), DestBucket);
- (void)FoundVal; // silence warning.
- CHECK(!FoundVal);
- DestBucket->getFirst() = __sanitizer::move(B->getFirst());
- ::new (&DestBucket->getSecond())
- ValueT(__sanitizer::move(B->getSecond()));
- incrementNumEntries();
- // Free the value.
- B->getSecond().~ValueT();
- }
- B->getFirst().~KeyT();
- }
- }
- template <typename OtherBaseT>
- void copyFrom(
- const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT, BucketT> &other) {
- CHECK_NE(&other, this);
- CHECK_EQ(getNumBuckets(), other.getNumBuckets());
- setNumEntries(other.getNumEntries());
- setNumTombstones(other.getNumTombstones());
- if (__sanitizer::is_trivially_copyable<KeyT>::value &&
- __sanitizer::is_trivially_copyable<ValueT>::value)
- internal_memcpy(reinterpret_cast<void *>(getBuckets()),
- other.getBuckets(), getNumBuckets() * sizeof(BucketT));
- else
- for (uptr i = 0; i < getNumBuckets(); ++i) {
- ::new (&getBuckets()[i].getFirst())
- KeyT(other.getBuckets()[i].getFirst());
- if (!KeyInfoT::isEqual(getBuckets()[i].getFirst(), getEmptyKey()) &&
- !KeyInfoT::isEqual(getBuckets()[i].getFirst(), getTombstoneKey()))
- ::new (&getBuckets()[i].getSecond())
- ValueT(other.getBuckets()[i].getSecond());
- }
- }
- static unsigned getHashValue(const KeyT &Val) {
- return KeyInfoT::getHashValue(Val);
- }
- template <typename LookupKeyT>
- static unsigned getHashValue(const LookupKeyT &Val) {
- return KeyInfoT::getHashValue(Val);
- }
- static const KeyT getEmptyKey() { return KeyInfoT::getEmptyKey(); }
- static const KeyT getTombstoneKey() { return KeyInfoT::getTombstoneKey(); }
- private:
- unsigned getNumEntries() const {
- return static_cast<const DerivedT *>(this)->getNumEntries();
- }
- void setNumEntries(unsigned Num) {
- static_cast<DerivedT *>(this)->setNumEntries(Num);
- }
- void incrementNumEntries() { setNumEntries(getNumEntries() + 1); }
- void decrementNumEntries() { setNumEntries(getNumEntries() - 1); }
- unsigned getNumTombstones() const {
- return static_cast<const DerivedT *>(this)->getNumTombstones();
- }
- void setNumTombstones(unsigned Num) {
- static_cast<DerivedT *>(this)->setNumTombstones(Num);
- }
- void incrementNumTombstones() { setNumTombstones(getNumTombstones() + 1); }
- void decrementNumTombstones() { setNumTombstones(getNumTombstones() - 1); }
- const BucketT *getBuckets() const {
- return static_cast<const DerivedT *>(this)->getBuckets();
- }
- BucketT *getBuckets() { return static_cast<DerivedT *>(this)->getBuckets(); }
- unsigned getNumBuckets() const {
- return static_cast<const DerivedT *>(this)->getNumBuckets();
- }
- BucketT *getBucketsEnd() { return getBuckets() + getNumBuckets(); }
- const BucketT *getBucketsEnd() const {
- return getBuckets() + getNumBuckets();
- }
- void grow(unsigned AtLeast) { static_cast<DerivedT *>(this)->grow(AtLeast); }
- template <typename KeyArg, typename... ValueArgs>
- BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
- ValueArgs &&...Values) {
- TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);
- TheBucket->getFirst() = __sanitizer::forward<KeyArg>(Key);
- ::new (&TheBucket->getSecond())
- ValueT(__sanitizer::forward<ValueArgs>(Values)...);
- return TheBucket;
- }
- template <typename LookupKeyT>
- BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key,
- ValueT &&Value, LookupKeyT &Lookup) {
- TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);
- TheBucket->getFirst() = __sanitizer::move(Key);
- ::new (&TheBucket->getSecond()) ValueT(__sanitizer::move(Value));
- return TheBucket;
- }
- template <typename LookupKeyT>
- BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup,
- BucketT *TheBucket) {
- // If the load of the hash table is more than 3/4, or if fewer than 1/8 of
- // the buckets are empty (meaning that many are filled with tombstones),
- // grow the table.
- //
- // The later case is tricky. For example, if we had one empty bucket with
- // tons of tombstones, failing lookups (e.g. for insertion) would have to
- // probe almost the entire table until it found the empty bucket. If the
- // table completely filled with tombstones, no lookup would ever succeed,
- // causing infinite loops in lookup.
- unsigned NewNumEntries = getNumEntries() + 1;
- unsigned NumBuckets = getNumBuckets();
- if (UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) {
- this->grow(NumBuckets * 2);
- LookupBucketFor(Lookup, TheBucket);
- NumBuckets = getNumBuckets();
- } else if (UNLIKELY(NumBuckets - (NewNumEntries + getNumTombstones()) <=
- NumBuckets / 8)) {
- this->grow(NumBuckets);
- LookupBucketFor(Lookup, TheBucket);
- }
- CHECK(TheBucket);
- // Only update the state after we've grown our bucket space appropriately
- // so that when growing buckets we have self-consistent entry count.
- incrementNumEntries();
- // If we are writing over a tombstone, remember this.
- const KeyT EmptyKey = getEmptyKey();
- if (!KeyInfoT::isEqual(TheBucket->getFirst(), EmptyKey))
- decrementNumTombstones();
- return TheBucket;
- }
- /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in
- /// FoundBucket. If the bucket contains the key and a value, this returns
- /// true, otherwise it returns a bucket with an empty marker or tombstone and
- /// returns false.
- template <typename LookupKeyT>
- bool LookupBucketFor(const LookupKeyT &Val,
- const BucketT *&FoundBucket) const {
- const BucketT *BucketsPtr = getBuckets();
- const unsigned NumBuckets = getNumBuckets();
- if (NumBuckets == 0) {
- FoundBucket = nullptr;
- return false;
- }
- // FoundTombstone - Keep track of whether we find a tombstone while probing.
- const BucketT *FoundTombstone = nullptr;
- const KeyT EmptyKey = getEmptyKey();
- const KeyT TombstoneKey = getTombstoneKey();
- CHECK(!KeyInfoT::isEqual(Val, EmptyKey));
- CHECK(!KeyInfoT::isEqual(Val, TombstoneKey));
- unsigned BucketNo = getHashValue(Val) & (NumBuckets - 1);
- unsigned ProbeAmt = 1;
- while (true) {
- const BucketT *ThisBucket = BucketsPtr + BucketNo;
- // Found Val's bucket? If so, return it.
- if (LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
- FoundBucket = ThisBucket;
- return true;
- }
- // If we found an empty bucket, the key doesn't exist in the set.
- // Insert it and return the default value.
- if (LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) {
- // If we've already seen a tombstone while probing, fill it in instead
- // of the empty bucket we eventually probed to.
- FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
- return false;
- }
- // If this is a tombstone, remember it. If Val ends up not in the map, we
- // prefer to return it than something that would require more probing.
- if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) &&
- !FoundTombstone)
- FoundTombstone = ThisBucket; // Remember the first tombstone found.
- // Otherwise, it's a hash collision or a tombstone, continue quadratic
- // probing.
- BucketNo += ProbeAmt++;
- BucketNo &= (NumBuckets - 1);
- }
- }
- template <typename LookupKeyT>
- bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) {
- const BucketT *ConstFoundBucket;
- bool Result = const_cast<const DenseMapBase *>(this)->LookupBucketFor(
- Val, ConstFoundBucket);
- FoundBucket = const_cast<BucketT *>(ConstFoundBucket);
- return Result;
- }
- public:
- /// Return the approximate size (in bytes) of the actual map.
- /// This is just the raw memory used by DenseMap.
- /// If entries are pointers to objects, the size of the referenced objects
- /// are not included.
- uptr getMemorySize() const {
- return RoundUpTo(getNumBuckets() * sizeof(BucketT), GetPageSizeCached());
- }
- };
- /// Equality comparison for DenseMap.
- ///
- /// Iterates over elements of LHS confirming that each (key, value) pair in LHS
- /// is also in RHS, and that no additional pairs are in RHS.
- /// Equivalent to N calls to RHS.find and N value comparisons. Amortized
- /// complexity is linear, worst case is O(N^2) (if every hash collides).
- template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
- typename BucketT>
- bool operator==(
- const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
- const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
- if (LHS.size() != RHS.size())
- return false;
- bool R = true;
- LHS.forEach(
- [&](const typename DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT,
- BucketT>::value_type &KV) -> bool {
- const auto *I = RHS.find(KV.first);
- if (!I || I->second != KV.second) {
- R = false;
- return false;
- }
- return true;
- });
- return R;
- }
- /// Inequality comparison for DenseMap.
- ///
- /// Equivalent to !(LHS == RHS). See operator== for performance notes.
- template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
- typename BucketT>
- bool operator!=(
- const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
- const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
- return !(LHS == RHS);
- }
- template <typename KeyT, typename ValueT,
- typename KeyInfoT = DenseMapInfo<KeyT>,
- typename BucketT = detail::DenseMapPair<KeyT, ValueT>>
- class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
- KeyT, ValueT, KeyInfoT, BucketT> {
- friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
- // Lift some types from the dependent base class into this class for
- // simplicity of referring to them.
- using BaseT = DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
- BucketT *Buckets = nullptr;
- unsigned NumEntries = 0;
- unsigned NumTombstones = 0;
- unsigned NumBuckets = 0;
- public:
- /// Create a DenseMap with an optional \p InitialReserve that guarantee that
- /// this number of elements can be inserted in the map without grow()
- explicit DenseMap(unsigned InitialReserve) { init(InitialReserve); }
- constexpr DenseMap() = default;
- DenseMap(const DenseMap &other) : BaseT() {
- init(0);
- copyFrom(other);
- }
- DenseMap(DenseMap &&other) : BaseT() {
- init(0);
- swap(other);
- }
- ~DenseMap() {
- this->destroyAll();
- deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets);
- }
- void swap(DenseMap &RHS) {
- Swap(Buckets, RHS.Buckets);
- Swap(NumEntries, RHS.NumEntries);
- Swap(NumTombstones, RHS.NumTombstones);
- Swap(NumBuckets, RHS.NumBuckets);
- }
- DenseMap &operator=(const DenseMap &other) {
- if (&other != this)
- copyFrom(other);
- return *this;
- }
- DenseMap &operator=(DenseMap &&other) {
- this->destroyAll();
- deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
- init(0);
- swap(other);
- return *this;
- }
- void copyFrom(const DenseMap &other) {
- this->destroyAll();
- deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets);
- if (allocateBuckets(other.NumBuckets)) {
- this->BaseT::copyFrom(other);
- } else {
- NumEntries = 0;
- NumTombstones = 0;
- }
- }
- void init(unsigned InitNumEntries) {
- auto InitBuckets = BaseT::getMinBucketToReserveForEntries(InitNumEntries);
- if (allocateBuckets(InitBuckets)) {
- this->BaseT::initEmpty();
- } else {
- NumEntries = 0;
- NumTombstones = 0;
- }
- }
- void grow(unsigned AtLeast) {
- unsigned OldNumBuckets = NumBuckets;
- BucketT *OldBuckets = Buckets;
- allocateBuckets(RoundUpToPowerOfTwo(Max<unsigned>(64, AtLeast)));
- CHECK(Buckets);
- if (!OldBuckets) {
- this->BaseT::initEmpty();
- return;
- }
- this->moveFromOldBuckets(OldBuckets, OldBuckets + OldNumBuckets);
- // Free the old table.
- deallocate_buffer(OldBuckets, sizeof(BucketT) * OldNumBuckets);
- }
- private:
- unsigned getNumEntries() const { return NumEntries; }
- void setNumEntries(unsigned Num) { NumEntries = Num; }
- unsigned getNumTombstones() const { return NumTombstones; }
- void setNumTombstones(unsigned Num) { NumTombstones = Num; }
- BucketT *getBuckets() const { return Buckets; }
- unsigned getNumBuckets() const { return NumBuckets; }
- bool allocateBuckets(unsigned Num) {
- NumBuckets = Num;
- if (NumBuckets == 0) {
- Buckets = nullptr;
- return false;
- }
- uptr Size = sizeof(BucketT) * NumBuckets;
- if (Size * 2 <= GetPageSizeCached()) {
- // We always allocate at least a page, so use entire space.
- unsigned Log2 = MostSignificantSetBitIndex(GetPageSizeCached() / Size);
- Size <<= Log2;
- NumBuckets <<= Log2;
- CHECK_EQ(Size, sizeof(BucketT) * NumBuckets);
- CHECK_GT(Size * 2, GetPageSizeCached());
- }
- Buckets = static_cast<BucketT *>(allocate_buffer(Size));
- return true;
- }
- static void *allocate_buffer(uptr Size) {
- return MmapOrDie(RoundUpTo(Size, GetPageSizeCached()), "DenseMap");
- }
- static void deallocate_buffer(void *Ptr, uptr Size) {
- UnmapOrDie(Ptr, RoundUpTo(Size, GetPageSizeCached()));
- }
- };
- } // namespace __sanitizer
- #endif // SANITIZER_DENSE_MAP_H
|