File indexing completed on 2026-05-10 08:43:03
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_ADT_DENSEMAP_H
0015 #define LLVM_ADT_DENSEMAP_H
0016
0017 #include "llvm/ADT/DenseMapInfo.h"
0018 #include "llvm/ADT/EpochTracker.h"
0019 #include "llvm/Support/AlignOf.h"
0020 #include "llvm/Support/Compiler.h"
0021 #include "llvm/Support/MathExtras.h"
0022 #include "llvm/Support/MemAlloc.h"
0023 #include "llvm/Support/ReverseIteration.h"
0024 #include "llvm/Support/type_traits.h"
0025 #include <algorithm>
0026 #include <cassert>
0027 #include <cstddef>
0028 #include <cstring>
0029 #include <initializer_list>
0030 #include <iterator>
0031 #include <new>
0032 #include <type_traits>
0033 #include <utility>
0034
0035 namespace llvm {
0036
0037 namespace detail {
0038
0039
0040
0041 template <typename KeyT, typename ValueT>
0042 struct DenseMapPair : public std::pair<KeyT, ValueT> {
0043 using std::pair<KeyT, ValueT>::pair;
0044
0045 KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; }
0046 const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; }
0047 ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
0048 const ValueT &getSecond() const { return std::pair<KeyT, ValueT>::second; }
0049 };
0050
0051 }
0052
0053 template <typename KeyT, typename ValueT,
0054 typename KeyInfoT = DenseMapInfo<KeyT>,
0055 typename Bucket = llvm::detail::DenseMapPair<KeyT, ValueT>,
0056 bool IsConst = false>
0057 class DenseMapIterator;
0058
0059 template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
0060 typename BucketT>
0061 class DenseMapBase : public DebugEpochBase {
0062 template <typename T>
0063 using const_arg_type_t = typename const_pointer_or_const_ref<T>::type;
0064
0065 public:
0066 using size_type = unsigned;
0067 using key_type = KeyT;
0068 using mapped_type = ValueT;
0069 using value_type = BucketT;
0070
0071 using iterator = DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT>;
0072 using const_iterator =
0073 DenseMapIterator<KeyT, ValueT, KeyInfoT, BucketT, true>;
0074
0075 inline iterator begin() {
0076
0077
0078 if (empty())
0079 return end();
0080 if (shouldReverseIterate<KeyT>())
0081 return makeIterator(getBucketsEnd() - 1, getBuckets(), *this);
0082 return makeIterator(getBuckets(), getBucketsEnd(), *this);
0083 }
0084 inline iterator end() {
0085 return makeIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
0086 }
0087 inline const_iterator begin() const {
0088 if (empty())
0089 return end();
0090 if (shouldReverseIterate<KeyT>())
0091 return makeConstIterator(getBucketsEnd() - 1, getBuckets(), *this);
0092 return makeConstIterator(getBuckets(), getBucketsEnd(), *this);
0093 }
0094 inline const_iterator end() const {
0095 return makeConstIterator(getBucketsEnd(), getBucketsEnd(), *this, true);
0096 }
0097
0098 [[nodiscard]] bool empty() const { return getNumEntries() == 0; }
0099 unsigned size() const { return getNumEntries(); }
0100
0101
0102
0103 void reserve(size_type NumEntries) {
0104 auto NumBuckets = getMinBucketToReserveForEntries(NumEntries);
0105 incrementEpoch();
0106 if (NumBuckets > getNumBuckets())
0107 grow(NumBuckets);
0108 }
0109
0110 void clear() {
0111 incrementEpoch();
0112 if (getNumEntries() == 0 && getNumTombstones() == 0)
0113 return;
0114
0115
0116
0117 if (getNumEntries() * 4 < getNumBuckets() && getNumBuckets() > 64) {
0118 shrink_and_clear();
0119 return;
0120 }
0121
0122 const KeyT EmptyKey = getEmptyKey();
0123 if constexpr (std::is_trivially_destructible_v<ValueT>) {
0124
0125 for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
0126 P->getFirst() = EmptyKey;
0127 } else {
0128 const KeyT TombstoneKey = getTombstoneKey();
0129 unsigned NumEntries = getNumEntries();
0130 for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
0131 if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) {
0132 if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
0133 P->getSecond().~ValueT();
0134 --NumEntries;
0135 }
0136 P->getFirst() = EmptyKey;
0137 }
0138 }
0139 assert(NumEntries == 0 && "Node count imbalance!");
0140 (void)NumEntries;
0141 }
0142 setNumEntries(0);
0143 setNumTombstones(0);
0144 }
0145
0146
0147 bool contains(const_arg_type_t<KeyT> Val) const {
0148 return doFind(Val) != nullptr;
0149 }
0150
0151
0152 size_type count(const_arg_type_t<KeyT> Val) const {
0153 return contains(Val) ? 1 : 0;
0154 }
0155
0156 iterator find(const_arg_type_t<KeyT> Val) {
0157 if (BucketT *Bucket = doFind(Val))
0158 return makeIterator(
0159 Bucket, shouldReverseIterate<KeyT>() ? getBuckets() : getBucketsEnd(),
0160 *this, true);
0161 return end();
0162 }
0163 const_iterator find(const_arg_type_t<KeyT> Val) const {
0164 if (const BucketT *Bucket = doFind(Val))
0165 return makeConstIterator(
0166 Bucket, shouldReverseIterate<KeyT>() ? getBuckets() : getBucketsEnd(),
0167 *this, true);
0168 return end();
0169 }
0170
0171
0172
0173
0174
0175
0176 template <class LookupKeyT> iterator find_as(const LookupKeyT &Val) {
0177 if (BucketT *Bucket = doFind(Val))
0178 return makeIterator(
0179 Bucket, shouldReverseIterate<KeyT>() ? getBuckets() : getBucketsEnd(),
0180 *this, true);
0181 return end();
0182 }
0183 template <class LookupKeyT>
0184 const_iterator find_as(const LookupKeyT &Val) const {
0185 if (const BucketT *Bucket = doFind(Val))
0186 return makeConstIterator(
0187 Bucket, shouldReverseIterate<KeyT>() ? getBuckets() : getBucketsEnd(),
0188 *this, true);
0189 return end();
0190 }
0191
0192
0193
0194 ValueT lookup(const_arg_type_t<KeyT> Val) const {
0195 if (const BucketT *Bucket = doFind(Val))
0196 return Bucket->getSecond();
0197 return ValueT();
0198 }
0199
0200
0201
0202 const ValueT &at(const_arg_type_t<KeyT> Val) const {
0203 auto Iter = this->find(std::move(Val));
0204 assert(Iter != this->end() && "DenseMap::at failed due to a missing key");
0205 return Iter->second;
0206 }
0207
0208
0209
0210
0211 std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
0212 return try_emplace(KV.first, KV.second);
0213 }
0214
0215
0216
0217
0218 std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
0219 return try_emplace(std::move(KV.first), std::move(KV.second));
0220 }
0221
0222
0223
0224
0225 template <typename... Ts>
0226 std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&...Args) {
0227 BucketT *TheBucket;
0228 if (LookupBucketFor(Key, TheBucket))
0229 return std::make_pair(makeIterator(TheBucket,
0230 shouldReverseIterate<KeyT>()
0231 ? getBuckets()
0232 : getBucketsEnd(),
0233 *this, true),
0234 false);
0235
0236
0237 TheBucket =
0238 InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
0239 return std::make_pair(makeIterator(TheBucket,
0240 shouldReverseIterate<KeyT>()
0241 ? getBuckets()
0242 : getBucketsEnd(),
0243 *this, true),
0244 true);
0245 }
0246
0247
0248
0249
0250 template <typename... Ts>
0251 std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&...Args) {
0252 BucketT *TheBucket;
0253 if (LookupBucketFor(Key, TheBucket))
0254 return std::make_pair(makeIterator(TheBucket,
0255 shouldReverseIterate<KeyT>()
0256 ? getBuckets()
0257 : getBucketsEnd(),
0258 *this, true),
0259 false);
0260
0261
0262 TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
0263 return std::make_pair(makeIterator(TheBucket,
0264 shouldReverseIterate<KeyT>()
0265 ? getBuckets()
0266 : getBucketsEnd(),
0267 *this, true),
0268 true);
0269 }
0270
0271
0272
0273
0274
0275
0276 template <typename LookupKeyT>
0277 std::pair<iterator, bool> insert_as(std::pair<KeyT, ValueT> &&KV,
0278 const LookupKeyT &Val) {
0279 BucketT *TheBucket;
0280 if (LookupBucketFor(Val, TheBucket))
0281 return std::make_pair(makeIterator(TheBucket,
0282 shouldReverseIterate<KeyT>()
0283 ? getBuckets()
0284 : getBucketsEnd(),
0285 *this, true),
0286 false);
0287
0288
0289 TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
0290 std::move(KV.second), Val);
0291 return std::make_pair(makeIterator(TheBucket,
0292 shouldReverseIterate<KeyT>()
0293 ? getBuckets()
0294 : getBucketsEnd(),
0295 *this, true),
0296 true);
0297 }
0298
0299
0300 template <typename InputIt> void insert(InputIt I, InputIt E) {
0301 for (; I != E; ++I)
0302 insert(*I);
0303 }
0304
0305 template <typename V>
0306 std::pair<iterator, bool> insert_or_assign(const KeyT &Key, V &&Val) {
0307 auto Ret = try_emplace(Key, std::forward<V>(Val));
0308 if (!Ret.second)
0309 Ret.first->second = std::forward<V>(Val);
0310 return Ret;
0311 }
0312
0313 template <typename V>
0314 std::pair<iterator, bool> insert_or_assign(KeyT &&Key, V &&Val) {
0315 auto Ret = try_emplace(std::move(Key), std::forward<V>(Val));
0316 if (!Ret.second)
0317 Ret.first->second = std::forward<V>(Val);
0318 return Ret;
0319 }
0320
0321 bool erase(const KeyT &Val) {
0322 BucketT *TheBucket = doFind(Val);
0323 if (!TheBucket)
0324 return false;
0325
0326 TheBucket->getSecond().~ValueT();
0327 TheBucket->getFirst() = getTombstoneKey();
0328 decrementNumEntries();
0329 incrementNumTombstones();
0330 return true;
0331 }
0332 void erase(iterator I) {
0333 BucketT *TheBucket = &*I;
0334 TheBucket->getSecond().~ValueT();
0335 TheBucket->getFirst() = getTombstoneKey();
0336 decrementNumEntries();
0337 incrementNumTombstones();
0338 }
0339
0340 ValueT &operator[](const KeyT &Key) {
0341 BucketT *TheBucket;
0342 if (LookupBucketFor(Key, TheBucket))
0343 return TheBucket->second;
0344
0345 return InsertIntoBucket(TheBucket, Key)->second;
0346 }
0347
0348 ValueT &operator[](KeyT &&Key) {
0349 BucketT *TheBucket;
0350 if (LookupBucketFor(Key, TheBucket))
0351 return TheBucket->second;
0352
0353 return InsertIntoBucket(TheBucket, std::move(Key))->second;
0354 }
0355
0356
0357
0358
0359 bool isPointerIntoBucketsArray(const void *Ptr) const {
0360 return Ptr >= getBuckets() && Ptr < getBucketsEnd();
0361 }
0362
0363
0364
0365
0366 const void *getPointerIntoBucketsArray() const { return getBuckets(); }
0367
0368 protected:
0369 DenseMapBase() = default;
0370
0371 void destroyAll() {
0372 if (getNumBuckets() == 0)
0373 return;
0374
0375 const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
0376 for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) {
0377 if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) &&
0378 !KeyInfoT::isEqual(P->getFirst(), TombstoneKey))
0379 P->getSecond().~ValueT();
0380 P->getFirst().~KeyT();
0381 }
0382 }
0383
0384 void initEmpty() {
0385 setNumEntries(0);
0386 setNumTombstones(0);
0387
0388 assert((getNumBuckets() & (getNumBuckets() - 1)) == 0 &&
0389 "# initial buckets must be a power of two!");
0390 const KeyT EmptyKey = getEmptyKey();
0391 for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B)
0392 ::new (&B->getFirst()) KeyT(EmptyKey);
0393 }
0394
0395
0396
0397 unsigned getMinBucketToReserveForEntries(unsigned NumEntries) {
0398
0399 if (NumEntries == 0)
0400 return 0;
0401
0402
0403 return NextPowerOf2(NumEntries * 4 / 3 + 1);
0404 }
0405
0406 void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) {
0407 initEmpty();
0408
0409
0410 const KeyT EmptyKey = getEmptyKey();
0411 const KeyT TombstoneKey = getTombstoneKey();
0412 for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) {
0413 if (!KeyInfoT::isEqual(B->getFirst(), EmptyKey) &&
0414 !KeyInfoT::isEqual(B->getFirst(), TombstoneKey)) {
0415
0416 BucketT *DestBucket;
0417 bool FoundVal = LookupBucketFor(B->getFirst(), DestBucket);
0418 (void)FoundVal;
0419 assert(!FoundVal && "Key already in new map?");
0420 DestBucket->getFirst() = std::move(B->getFirst());
0421 ::new (&DestBucket->getSecond()) ValueT(std::move(B->getSecond()));
0422 incrementNumEntries();
0423
0424
0425 B->getSecond().~ValueT();
0426 }
0427 B->getFirst().~KeyT();
0428 }
0429 }
0430
0431 template <typename OtherBaseT>
0432 void copyFrom(
0433 const DenseMapBase<OtherBaseT, KeyT, ValueT, KeyInfoT, BucketT> &other) {
0434 assert(&other != this);
0435 assert(getNumBuckets() == other.getNumBuckets());
0436
0437 setNumEntries(other.getNumEntries());
0438 setNumTombstones(other.getNumTombstones());
0439
0440 BucketT *Buckets = getBuckets();
0441 const BucketT *OtherBuckets = other.getBuckets();
0442 const size_t NumBuckets = getNumBuckets();
0443 if constexpr (std::is_trivially_copyable_v<KeyT> &&
0444 std::is_trivially_copyable_v<ValueT>) {
0445 memcpy(reinterpret_cast<void *>(Buckets), OtherBuckets,
0446 NumBuckets * sizeof(BucketT));
0447 } else {
0448 const KeyT EmptyKey = getEmptyKey();
0449 const KeyT TombstoneKey = getTombstoneKey();
0450 for (size_t I = 0; I < NumBuckets; ++I) {
0451 ::new (&Buckets[I].getFirst()) KeyT(OtherBuckets[I].getFirst());
0452 if (!KeyInfoT::isEqual(Buckets[I].getFirst(), EmptyKey) &&
0453 !KeyInfoT::isEqual(Buckets[I].getFirst(), TombstoneKey))
0454 ::new (&Buckets[I].getSecond()) ValueT(OtherBuckets[I].getSecond());
0455 }
0456 }
0457 }
0458
0459 static unsigned getHashValue(const KeyT &Val) {
0460 return KeyInfoT::getHashValue(Val);
0461 }
0462
0463 template <typename LookupKeyT>
0464 static unsigned getHashValue(const LookupKeyT &Val) {
0465 return KeyInfoT::getHashValue(Val);
0466 }
0467
0468 static const KeyT getEmptyKey() {
0469 static_assert(std::is_base_of_v<DenseMapBase, DerivedT>,
0470 "Must pass the derived type to this template!");
0471 return KeyInfoT::getEmptyKey();
0472 }
0473
0474 static const KeyT getTombstoneKey() { return KeyInfoT::getTombstoneKey(); }
0475
0476 private:
0477 iterator makeIterator(BucketT *P, BucketT *E, DebugEpochBase &Epoch,
0478 bool NoAdvance = false) {
0479 if (shouldReverseIterate<KeyT>()) {
0480 BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
0481 return iterator(B, E, Epoch, NoAdvance);
0482 }
0483 return iterator(P, E, Epoch, NoAdvance);
0484 }
0485
0486 const_iterator makeConstIterator(const BucketT *P, const BucketT *E,
0487 const DebugEpochBase &Epoch,
0488 const bool NoAdvance = false) const {
0489 if (shouldReverseIterate<KeyT>()) {
0490 const BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
0491 return const_iterator(B, E, Epoch, NoAdvance);
0492 }
0493 return const_iterator(P, E, Epoch, NoAdvance);
0494 }
0495
0496 unsigned getNumEntries() const {
0497 return static_cast<const DerivedT *>(this)->getNumEntries();
0498 }
0499
0500 void setNumEntries(unsigned Num) {
0501 static_cast<DerivedT *>(this)->setNumEntries(Num);
0502 }
0503
0504 void incrementNumEntries() { setNumEntries(getNumEntries() + 1); }
0505
0506 void decrementNumEntries() { setNumEntries(getNumEntries() - 1); }
0507
0508 unsigned getNumTombstones() const {
0509 return static_cast<const DerivedT *>(this)->getNumTombstones();
0510 }
0511
0512 void setNumTombstones(unsigned Num) {
0513 static_cast<DerivedT *>(this)->setNumTombstones(Num);
0514 }
0515
0516 void incrementNumTombstones() { setNumTombstones(getNumTombstones() + 1); }
0517
0518 void decrementNumTombstones() { setNumTombstones(getNumTombstones() - 1); }
0519
0520 const BucketT *getBuckets() const {
0521 return static_cast<const DerivedT *>(this)->getBuckets();
0522 }
0523
0524 BucketT *getBuckets() { return static_cast<DerivedT *>(this)->getBuckets(); }
0525
0526 unsigned getNumBuckets() const {
0527 return static_cast<const DerivedT *>(this)->getNumBuckets();
0528 }
0529
0530 BucketT *getBucketsEnd() { return getBuckets() + getNumBuckets(); }
0531
0532 const BucketT *getBucketsEnd() const {
0533 return getBuckets() + getNumBuckets();
0534 }
0535
0536 void grow(unsigned AtLeast) { static_cast<DerivedT *>(this)->grow(AtLeast); }
0537
0538 void shrink_and_clear() { static_cast<DerivedT *>(this)->shrink_and_clear(); }
0539
0540 template <typename KeyArg, typename... ValueArgs>
0541 BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
0542 ValueArgs &&...Values) {
0543 TheBucket = InsertIntoBucketImpl(Key, TheBucket);
0544
0545 TheBucket->getFirst() = std::forward<KeyArg>(Key);
0546 ::new (&TheBucket->getSecond()) ValueT(std::forward<ValueArgs>(Values)...);
0547 return TheBucket;
0548 }
0549
0550 template <typename LookupKeyT>
0551 BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key,
0552 ValueT &&Value, LookupKeyT &Lookup) {
0553 TheBucket = InsertIntoBucketImpl(Lookup, TheBucket);
0554
0555 TheBucket->getFirst() = std::move(Key);
0556 ::new (&TheBucket->getSecond()) ValueT(std::move(Value));
0557 return TheBucket;
0558 }
0559
0560 template <typename LookupKeyT>
0561 BucketT *InsertIntoBucketImpl(const LookupKeyT &Lookup, BucketT *TheBucket) {
0562 incrementEpoch();
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573 unsigned NewNumEntries = getNumEntries() + 1;
0574 unsigned NumBuckets = getNumBuckets();
0575 if (LLVM_UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) {
0576 this->grow(NumBuckets * 2);
0577 LookupBucketFor(Lookup, TheBucket);
0578 NumBuckets = getNumBuckets();
0579 } else if (LLVM_UNLIKELY(NumBuckets -
0580 (NewNumEntries + getNumTombstones()) <=
0581 NumBuckets / 8)) {
0582 this->grow(NumBuckets);
0583 LookupBucketFor(Lookup, TheBucket);
0584 }
0585 assert(TheBucket);
0586
0587
0588
0589 incrementNumEntries();
0590
0591
0592 const KeyT EmptyKey = getEmptyKey();
0593 if (!KeyInfoT::isEqual(TheBucket->getFirst(), EmptyKey))
0594 decrementNumTombstones();
0595
0596 return TheBucket;
0597 }
0598
0599 template <typename LookupKeyT> BucketT *doFind(const LookupKeyT &Val) {
0600 BucketT *BucketsPtr = getBuckets();
0601 const unsigned NumBuckets = getNumBuckets();
0602 if (NumBuckets == 0)
0603 return nullptr;
0604
0605 const KeyT EmptyKey = getEmptyKey();
0606 unsigned BucketNo = getHashValue(Val) & (NumBuckets - 1);
0607 unsigned ProbeAmt = 1;
0608 while (true) {
0609 BucketT *Bucket = BucketsPtr + BucketNo;
0610 if (LLVM_LIKELY(KeyInfoT::isEqual(Val, Bucket->getFirst())))
0611 return Bucket;
0612 if (LLVM_LIKELY(KeyInfoT::isEqual(Bucket->getFirst(), EmptyKey)))
0613 return nullptr;
0614
0615
0616
0617 BucketNo += ProbeAmt++;
0618 BucketNo &= NumBuckets - 1;
0619 }
0620 }
0621
0622 template <typename LookupKeyT>
0623 const BucketT *doFind(const LookupKeyT &Val) const {
0624 return const_cast<DenseMapBase *>(this)->doFind(Val);
0625 }
0626
0627
0628
0629
0630
0631 template <typename LookupKeyT>
0632 bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) {
0633 BucketT *BucketsPtr = getBuckets();
0634 const unsigned NumBuckets = getNumBuckets();
0635
0636 if (NumBuckets == 0) {
0637 FoundBucket = nullptr;
0638 return false;
0639 }
0640
0641
0642 BucketT *FoundTombstone = nullptr;
0643 const KeyT EmptyKey = getEmptyKey();
0644 const KeyT TombstoneKey = getTombstoneKey();
0645 assert(!KeyInfoT::isEqual(Val, EmptyKey) &&
0646 !KeyInfoT::isEqual(Val, TombstoneKey) &&
0647 "Empty/Tombstone value shouldn't be inserted into map!");
0648
0649 unsigned BucketNo = getHashValue(Val) & (NumBuckets - 1);
0650 unsigned ProbeAmt = 1;
0651 while (true) {
0652 BucketT *ThisBucket = BucketsPtr + BucketNo;
0653
0654 if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) {
0655 FoundBucket = ThisBucket;
0656 return true;
0657 }
0658
0659
0660
0661 if (LLVM_LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) {
0662
0663
0664 FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket;
0665 return false;
0666 }
0667
0668
0669
0670 if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) &&
0671 !FoundTombstone)
0672 FoundTombstone = ThisBucket;
0673
0674
0675
0676 BucketNo += ProbeAmt++;
0677 BucketNo &= (NumBuckets - 1);
0678 }
0679 }
0680
0681 public:
0682
0683
0684
0685
0686 size_t getMemorySize() const { return getNumBuckets() * sizeof(BucketT); }
0687 };
0688
0689
0690
0691
0692
0693
0694
0695 template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
0696 typename BucketT>
0697 bool operator==(
0698 const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
0699 const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
0700 if (LHS.size() != RHS.size())
0701 return false;
0702
0703 for (auto &KV : LHS) {
0704 auto I = RHS.find(KV.first);
0705 if (I == RHS.end() || I->second != KV.second)
0706 return false;
0707 }
0708
0709 return true;
0710 }
0711
0712
0713
0714
0715 template <typename DerivedT, typename KeyT, typename ValueT, typename KeyInfoT,
0716 typename BucketT>
0717 bool operator!=(
0718 const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &LHS,
0719 const DenseMapBase<DerivedT, KeyT, ValueT, KeyInfoT, BucketT> &RHS) {
0720 return !(LHS == RHS);
0721 }
0722
0723 template <typename KeyT, typename ValueT,
0724 typename KeyInfoT = DenseMapInfo<KeyT>,
0725 typename BucketT = llvm::detail::DenseMapPair<KeyT, ValueT>>
0726 class DenseMap : public DenseMapBase<DenseMap<KeyT, ValueT, KeyInfoT, BucketT>,
0727 KeyT, ValueT, KeyInfoT, BucketT> {
0728 friend class DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
0729
0730
0731
0732 using BaseT = DenseMapBase<DenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
0733
0734 BucketT *Buckets;
0735 unsigned NumEntries;
0736 unsigned NumTombstones;
0737 unsigned NumBuckets;
0738
0739 public:
0740
0741
0742 explicit DenseMap(unsigned InitialReserve = 0) { init(InitialReserve); }
0743
0744 DenseMap(const DenseMap &other) : BaseT() {
0745 init(0);
0746 copyFrom(other);
0747 }
0748
0749 DenseMap(DenseMap &&other) : BaseT() {
0750 init(0);
0751 swap(other);
0752 }
0753
0754 template <typename InputIt> DenseMap(const InputIt &I, const InputIt &E) {
0755 init(std::distance(I, E));
0756 this->insert(I, E);
0757 }
0758
0759 DenseMap(std::initializer_list<typename BaseT::value_type> Vals) {
0760 init(Vals.size());
0761 this->insert(Vals.begin(), Vals.end());
0762 }
0763
0764 ~DenseMap() {
0765 this->destroyAll();
0766 deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
0767 }
0768
0769 void swap(DenseMap &RHS) {
0770 this->incrementEpoch();
0771 RHS.incrementEpoch();
0772 std::swap(Buckets, RHS.Buckets);
0773 std::swap(NumEntries, RHS.NumEntries);
0774 std::swap(NumTombstones, RHS.NumTombstones);
0775 std::swap(NumBuckets, RHS.NumBuckets);
0776 }
0777
0778 DenseMap &operator=(const DenseMap &other) {
0779 if (&other != this)
0780 copyFrom(other);
0781 return *this;
0782 }
0783
0784 DenseMap &operator=(DenseMap &&other) {
0785 this->destroyAll();
0786 deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
0787 init(0);
0788 swap(other);
0789 return *this;
0790 }
0791
0792 void copyFrom(const DenseMap &other) {
0793 this->destroyAll();
0794 deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
0795 if (allocateBuckets(other.NumBuckets)) {
0796 this->BaseT::copyFrom(other);
0797 } else {
0798 NumEntries = 0;
0799 NumTombstones = 0;
0800 }
0801 }
0802
0803 void init(unsigned InitNumEntries) {
0804 auto InitBuckets = BaseT::getMinBucketToReserveForEntries(InitNumEntries);
0805 if (allocateBuckets(InitBuckets)) {
0806 this->BaseT::initEmpty();
0807 } else {
0808 NumEntries = 0;
0809 NumTombstones = 0;
0810 }
0811 }
0812
0813 void grow(unsigned AtLeast) {
0814 unsigned OldNumBuckets = NumBuckets;
0815 BucketT *OldBuckets = Buckets;
0816
0817 allocateBuckets(std::max<unsigned>(
0818 64, static_cast<unsigned>(NextPowerOf2(AtLeast - 1))));
0819 assert(Buckets);
0820 if (!OldBuckets) {
0821 this->BaseT::initEmpty();
0822 return;
0823 }
0824
0825 this->moveFromOldBuckets(OldBuckets, OldBuckets + OldNumBuckets);
0826
0827
0828 deallocate_buffer(OldBuckets, sizeof(BucketT) * OldNumBuckets,
0829 alignof(BucketT));
0830 }
0831
0832 void shrink_and_clear() {
0833 unsigned OldNumBuckets = NumBuckets;
0834 unsigned OldNumEntries = NumEntries;
0835 this->destroyAll();
0836
0837
0838 unsigned NewNumBuckets = 0;
0839 if (OldNumEntries)
0840 NewNumBuckets = std::max(64, 1 << (Log2_32_Ceil(OldNumEntries) + 1));
0841 if (NewNumBuckets == NumBuckets) {
0842 this->BaseT::initEmpty();
0843 return;
0844 }
0845
0846 deallocate_buffer(Buckets, sizeof(BucketT) * OldNumBuckets,
0847 alignof(BucketT));
0848 init(NewNumBuckets);
0849 }
0850
0851 private:
0852 unsigned getNumEntries() const { return NumEntries; }
0853
0854 void setNumEntries(unsigned Num) { NumEntries = Num; }
0855
0856 unsigned getNumTombstones() const { return NumTombstones; }
0857
0858 void setNumTombstones(unsigned Num) { NumTombstones = Num; }
0859
0860 BucketT *getBuckets() const { return Buckets; }
0861
0862 unsigned getNumBuckets() const { return NumBuckets; }
0863
0864 bool allocateBuckets(unsigned Num) {
0865 NumBuckets = Num;
0866 if (NumBuckets == 0) {
0867 Buckets = nullptr;
0868 return false;
0869 }
0870
0871 Buckets = static_cast<BucketT *>(
0872 allocate_buffer(sizeof(BucketT) * NumBuckets, alignof(BucketT)));
0873 return true;
0874 }
0875 };
0876
0877 template <typename KeyT, typename ValueT, unsigned InlineBuckets = 4,
0878 typename KeyInfoT = DenseMapInfo<KeyT>,
0879 typename BucketT = llvm::detail::DenseMapPair<KeyT, ValueT>>
0880 class SmallDenseMap
0881 : public DenseMapBase<
0882 SmallDenseMap<KeyT, ValueT, InlineBuckets, KeyInfoT, BucketT>, KeyT,
0883 ValueT, KeyInfoT, BucketT> {
0884 friend class DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
0885
0886
0887
0888 using BaseT = DenseMapBase<SmallDenseMap, KeyT, ValueT, KeyInfoT, BucketT>;
0889
0890 static_assert(isPowerOf2_64(InlineBuckets),
0891 "InlineBuckets must be a power of 2.");
0892
0893 unsigned Small : 1;
0894 unsigned NumEntries : 31;
0895 unsigned NumTombstones;
0896
0897 struct LargeRep {
0898 BucketT *Buckets;
0899 unsigned NumBuckets;
0900 };
0901
0902
0903
0904 AlignedCharArrayUnion<BucketT[InlineBuckets], LargeRep> storage;
0905
0906 public:
0907 explicit SmallDenseMap(unsigned NumInitBuckets = 0) {
0908 if (NumInitBuckets > InlineBuckets)
0909 NumInitBuckets = llvm::bit_ceil(NumInitBuckets);
0910 init(NumInitBuckets);
0911 }
0912
0913 SmallDenseMap(const SmallDenseMap &other) : BaseT() {
0914 init(0);
0915 copyFrom(other);
0916 }
0917
0918 SmallDenseMap(SmallDenseMap &&other) : BaseT() {
0919 init(0);
0920 swap(other);
0921 }
0922
0923 template <typename InputIt>
0924 SmallDenseMap(const InputIt &I, const InputIt &E) {
0925 init(NextPowerOf2(std::distance(I, E)));
0926 this->insert(I, E);
0927 }
0928
0929 SmallDenseMap(std::initializer_list<typename BaseT::value_type> Vals)
0930 : SmallDenseMap(Vals.begin(), Vals.end()) {}
0931
0932 ~SmallDenseMap() {
0933 this->destroyAll();
0934 deallocateBuckets();
0935 }
0936
0937 void swap(SmallDenseMap &RHS) {
0938 unsigned TmpNumEntries = RHS.NumEntries;
0939 RHS.NumEntries = NumEntries;
0940 NumEntries = TmpNumEntries;
0941 std::swap(NumTombstones, RHS.NumTombstones);
0942
0943 const KeyT EmptyKey = this->getEmptyKey();
0944 const KeyT TombstoneKey = this->getTombstoneKey();
0945 if (Small && RHS.Small) {
0946
0947
0948
0949
0950 for (unsigned i = 0, e = InlineBuckets; i != e; ++i) {
0951 BucketT *LHSB = &getInlineBuckets()[i],
0952 *RHSB = &RHS.getInlineBuckets()[i];
0953 bool hasLHSValue = (!KeyInfoT::isEqual(LHSB->getFirst(), EmptyKey) &&
0954 !KeyInfoT::isEqual(LHSB->getFirst(), TombstoneKey));
0955 bool hasRHSValue = (!KeyInfoT::isEqual(RHSB->getFirst(), EmptyKey) &&
0956 !KeyInfoT::isEqual(RHSB->getFirst(), TombstoneKey));
0957 if (hasLHSValue && hasRHSValue) {
0958
0959 std::swap(*LHSB, *RHSB);
0960 continue;
0961 }
0962
0963 std::swap(LHSB->getFirst(), RHSB->getFirst());
0964 if (hasLHSValue) {
0965 ::new (&RHSB->getSecond()) ValueT(std::move(LHSB->getSecond()));
0966 LHSB->getSecond().~ValueT();
0967 } else if (hasRHSValue) {
0968 ::new (&LHSB->getSecond()) ValueT(std::move(RHSB->getSecond()));
0969 RHSB->getSecond().~ValueT();
0970 }
0971 }
0972 return;
0973 }
0974 if (!Small && !RHS.Small) {
0975 std::swap(getLargeRep()->Buckets, RHS.getLargeRep()->Buckets);
0976 std::swap(getLargeRep()->NumBuckets, RHS.getLargeRep()->NumBuckets);
0977 return;
0978 }
0979
0980 SmallDenseMap &SmallSide = Small ? *this : RHS;
0981 SmallDenseMap &LargeSide = Small ? RHS : *this;
0982
0983
0984 LargeRep TmpRep = std::move(*LargeSide.getLargeRep());
0985 LargeSide.getLargeRep()->~LargeRep();
0986 LargeSide.Small = true;
0987
0988
0989
0990
0991 for (unsigned i = 0, e = InlineBuckets; i != e; ++i) {
0992 BucketT *NewB = &LargeSide.getInlineBuckets()[i],
0993 *OldB = &SmallSide.getInlineBuckets()[i];
0994 ::new (&NewB->getFirst()) KeyT(std::move(OldB->getFirst()));
0995 OldB->getFirst().~KeyT();
0996 if (!KeyInfoT::isEqual(NewB->getFirst(), EmptyKey) &&
0997 !KeyInfoT::isEqual(NewB->getFirst(), TombstoneKey)) {
0998 ::new (&NewB->getSecond()) ValueT(std::move(OldB->getSecond()));
0999 OldB->getSecond().~ValueT();
1000 }
1001 }
1002
1003
1004
1005 SmallSide.Small = false;
1006 new (SmallSide.getLargeRep()) LargeRep(std::move(TmpRep));
1007 }
1008
1009 SmallDenseMap &operator=(const SmallDenseMap &other) {
1010 if (&other != this)
1011 copyFrom(other);
1012 return *this;
1013 }
1014
1015 SmallDenseMap &operator=(SmallDenseMap &&other) {
1016 this->destroyAll();
1017 deallocateBuckets();
1018 init(0);
1019 swap(other);
1020 return *this;
1021 }
1022
1023 void copyFrom(const SmallDenseMap &other) {
1024 this->destroyAll();
1025 deallocateBuckets();
1026 Small = true;
1027 if (other.getNumBuckets() > InlineBuckets) {
1028 Small = false;
1029 new (getLargeRep()) LargeRep(allocateBuckets(other.getNumBuckets()));
1030 }
1031 this->BaseT::copyFrom(other);
1032 }
1033
1034 void init(unsigned InitBuckets) {
1035 Small = true;
1036 if (InitBuckets > InlineBuckets) {
1037 Small = false;
1038 new (getLargeRep()) LargeRep(allocateBuckets(InitBuckets));
1039 }
1040 this->BaseT::initEmpty();
1041 }
1042
1043 void grow(unsigned AtLeast) {
1044 if (AtLeast > InlineBuckets)
1045 AtLeast = std::max<unsigned>(64, NextPowerOf2(AtLeast - 1));
1046
1047 if (Small) {
1048
1049 AlignedCharArrayUnion<BucketT[InlineBuckets]> TmpStorage;
1050 BucketT *TmpBegin = reinterpret_cast<BucketT *>(&TmpStorage);
1051 BucketT *TmpEnd = TmpBegin;
1052
1053
1054
1055 const KeyT EmptyKey = this->getEmptyKey();
1056 const KeyT TombstoneKey = this->getTombstoneKey();
1057 for (BucketT *P = getBuckets(), *E = P + InlineBuckets; P != E; ++P) {
1058 if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) &&
1059 !KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) {
1060 assert(size_t(TmpEnd - TmpBegin) < InlineBuckets &&
1061 "Too many inline buckets!");
1062 ::new (&TmpEnd->getFirst()) KeyT(std::move(P->getFirst()));
1063 ::new (&TmpEnd->getSecond()) ValueT(std::move(P->getSecond()));
1064 ++TmpEnd;
1065 P->getSecond().~ValueT();
1066 }
1067 P->getFirst().~KeyT();
1068 }
1069
1070
1071
1072
1073 if (AtLeast > InlineBuckets) {
1074 Small = false;
1075 new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));
1076 }
1077 this->moveFromOldBuckets(TmpBegin, TmpEnd);
1078 return;
1079 }
1080
1081 LargeRep OldRep = std::move(*getLargeRep());
1082 getLargeRep()->~LargeRep();
1083 if (AtLeast <= InlineBuckets) {
1084 Small = true;
1085 } else {
1086 new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));
1087 }
1088
1089 this->moveFromOldBuckets(OldRep.Buckets,
1090 OldRep.Buckets + OldRep.NumBuckets);
1091
1092
1093 deallocate_buffer(OldRep.Buckets, sizeof(BucketT) * OldRep.NumBuckets,
1094 alignof(BucketT));
1095 }
1096
1097 void shrink_and_clear() {
1098 unsigned OldSize = this->size();
1099 this->destroyAll();
1100
1101
1102 unsigned NewNumBuckets = 0;
1103 if (OldSize) {
1104 NewNumBuckets = 1 << (Log2_32_Ceil(OldSize) + 1);
1105 if (NewNumBuckets > InlineBuckets && NewNumBuckets < 64u)
1106 NewNumBuckets = 64;
1107 }
1108 if ((Small && NewNumBuckets <= InlineBuckets) ||
1109 (!Small && NewNumBuckets == getLargeRep()->NumBuckets)) {
1110 this->BaseT::initEmpty();
1111 return;
1112 }
1113
1114 deallocateBuckets();
1115 init(NewNumBuckets);
1116 }
1117
1118 private:
1119 unsigned getNumEntries() const { return NumEntries; }
1120
1121 void setNumEntries(unsigned Num) {
1122
1123 assert(Num < (1U << 31) && "Cannot support more than 1<<31 entries");
1124 NumEntries = Num;
1125 }
1126
1127 unsigned getNumTombstones() const { return NumTombstones; }
1128
1129 void setNumTombstones(unsigned Num) { NumTombstones = Num; }
1130
1131 const BucketT *getInlineBuckets() const {
1132 assert(Small);
1133
1134
1135
1136 return reinterpret_cast<const BucketT *>(&storage);
1137 }
1138
1139 BucketT *getInlineBuckets() {
1140 return const_cast<BucketT *>(
1141 const_cast<const SmallDenseMap *>(this)->getInlineBuckets());
1142 }
1143
1144 const LargeRep *getLargeRep() const {
1145 assert(!Small);
1146
1147 return reinterpret_cast<const LargeRep *>(&storage);
1148 }
1149
1150 LargeRep *getLargeRep() {
1151 return const_cast<LargeRep *>(
1152 const_cast<const SmallDenseMap *>(this)->getLargeRep());
1153 }
1154
1155 const BucketT *getBuckets() const {
1156 return Small ? getInlineBuckets() : getLargeRep()->Buckets;
1157 }
1158
1159 BucketT *getBuckets() {
1160 return const_cast<BucketT *>(
1161 const_cast<const SmallDenseMap *>(this)->getBuckets());
1162 }
1163
1164 unsigned getNumBuckets() const {
1165 return Small ? InlineBuckets : getLargeRep()->NumBuckets;
1166 }
1167
1168 void deallocateBuckets() {
1169 if (Small)
1170 return;
1171
1172 deallocate_buffer(getLargeRep()->Buckets,
1173 sizeof(BucketT) * getLargeRep()->NumBuckets,
1174 alignof(BucketT));
1175 getLargeRep()->~LargeRep();
1176 }
1177
1178 LargeRep allocateBuckets(unsigned Num) {
1179 assert(Num > InlineBuckets && "Must allocate more buckets than are inline");
1180 LargeRep Rep = {static_cast<BucketT *>(allocate_buffer(
1181 sizeof(BucketT) * Num, alignof(BucketT))),
1182 Num};
1183 return Rep;
1184 }
1185 };
1186
1187 template <typename KeyT, typename ValueT, typename KeyInfoT, typename Bucket,
1188 bool IsConst>
1189 class DenseMapIterator : DebugEpochBase::HandleBase {
1190 friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
1191 friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>;
1192
1193 public:
1194 using difference_type = ptrdiff_t;
1195 using value_type = std::conditional_t<IsConst, const Bucket, Bucket>;
1196 using pointer = value_type *;
1197 using reference = value_type &;
1198 using iterator_category = std::forward_iterator_tag;
1199
1200 private:
1201 pointer Ptr = nullptr;
1202 pointer End = nullptr;
1203
1204 public:
1205 DenseMapIterator() = default;
1206
1207 DenseMapIterator(pointer Pos, pointer E, const DebugEpochBase &Epoch,
1208 bool NoAdvance = false)
1209 : DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) {
1210 assert(isHandleInSync() && "invalid construction!");
1211
1212 if (NoAdvance)
1213 return;
1214 if (shouldReverseIterate<KeyT>()) {
1215 RetreatPastEmptyBuckets();
1216 return;
1217 }
1218 AdvancePastEmptyBuckets();
1219 }
1220
1221
1222
1223
1224 template <bool IsConstSrc,
1225 typename = std::enable_if_t<!IsConstSrc && IsConst>>
1226 DenseMapIterator(
1227 const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConstSrc> &I)
1228 : DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End) {}
1229
1230 reference operator*() const {
1231 assert(isHandleInSync() && "invalid iterator access!");
1232 assert(Ptr != End && "dereferencing end() iterator");
1233 if (shouldReverseIterate<KeyT>())
1234 return Ptr[-1];
1235 return *Ptr;
1236 }
1237 pointer operator->() const {
1238 assert(isHandleInSync() && "invalid iterator access!");
1239 assert(Ptr != End && "dereferencing end() iterator");
1240 if (shouldReverseIterate<KeyT>())
1241 return &(Ptr[-1]);
1242 return Ptr;
1243 }
1244
1245 friend bool operator==(const DenseMapIterator &LHS,
1246 const DenseMapIterator &RHS) {
1247 assert((!LHS.Ptr || LHS.isHandleInSync()) && "handle not in sync!");
1248 assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
1249 assert(LHS.getEpochAddress() == RHS.getEpochAddress() &&
1250 "comparing incomparable iterators!");
1251 return LHS.Ptr == RHS.Ptr;
1252 }
1253
1254 friend bool operator!=(const DenseMapIterator &LHS,
1255 const DenseMapIterator &RHS) {
1256 return !(LHS == RHS);
1257 }
1258
1259 inline DenseMapIterator &operator++() {
1260 assert(isHandleInSync() && "invalid iterator access!");
1261 assert(Ptr != End && "incrementing end() iterator");
1262 if (shouldReverseIterate<KeyT>()) {
1263 --Ptr;
1264 RetreatPastEmptyBuckets();
1265 return *this;
1266 }
1267 ++Ptr;
1268 AdvancePastEmptyBuckets();
1269 return *this;
1270 }
1271 DenseMapIterator operator++(int) {
1272 assert(isHandleInSync() && "invalid iterator access!");
1273 DenseMapIterator tmp = *this;
1274 ++*this;
1275 return tmp;
1276 }
1277
1278 private:
1279 void AdvancePastEmptyBuckets() {
1280 assert(Ptr <= End);
1281 const KeyT Empty = KeyInfoT::getEmptyKey();
1282 const KeyT Tombstone = KeyInfoT::getTombstoneKey();
1283
1284 while (Ptr != End && (KeyInfoT::isEqual(Ptr->getFirst(), Empty) ||
1285 KeyInfoT::isEqual(Ptr->getFirst(), Tombstone)))
1286 ++Ptr;
1287 }
1288
1289 void RetreatPastEmptyBuckets() {
1290 assert(Ptr >= End);
1291 const KeyT Empty = KeyInfoT::getEmptyKey();
1292 const KeyT Tombstone = KeyInfoT::getTombstoneKey();
1293
1294 while (Ptr != End && (KeyInfoT::isEqual(Ptr[-1].getFirst(), Empty) ||
1295 KeyInfoT::isEqual(Ptr[-1].getFirst(), Tombstone)))
1296 --Ptr;
1297 }
1298 };
1299
1300 template <typename KeyT, typename ValueT, typename KeyInfoT>
1301 inline size_t capacity_in_bytes(const DenseMap<KeyT, ValueT, KeyInfoT> &X) {
1302 return X.getMemorySize();
1303 }
1304
1305 }
1306
1307 #endif