File indexing completed on 2026-05-10 08:43:04
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #ifndef LLVM_ADT_FOLDINGSET_H
0017 #define LLVM_ADT_FOLDINGSET_H
0018
0019 #include "llvm/ADT/Hashing.h"
0020 #include "llvm/ADT/STLForwardCompat.h"
0021 #include "llvm/ADT/SmallVector.h"
0022 #include "llvm/ADT/iterator.h"
0023 #include "llvm/Support/Allocator.h"
0024 #include "llvm/Support/xxhash.h"
0025 #include <cassert>
0026 #include <cstddef>
0027 #include <cstdint>
0028 #include <type_traits>
0029 #include <utility>
0030
0031 namespace llvm {
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 class FoldingSetNodeID;
0108 class StringRef;
0109
0110
0111
0112
0113
0114
0115
0116
0117 class FoldingSetBase {
0118 protected:
0119
0120 void **Buckets;
0121
0122
0123 unsigned NumBuckets;
0124
0125
0126
0127 unsigned NumNodes;
0128
0129 explicit FoldingSetBase(unsigned Log2InitSize = 6);
0130 FoldingSetBase(FoldingSetBase &&Arg);
0131 FoldingSetBase &operator=(FoldingSetBase &&RHS);
0132 ~FoldingSetBase();
0133
0134 public:
0135
0136
0137
0138 class Node {
0139 private:
0140
0141 void *NextInFoldingSetBucket = nullptr;
0142
0143 public:
0144 Node() = default;
0145
0146
0147 void *getNextInBucket() const { return NextInFoldingSetBucket; }
0148 void SetNextInBucket(void *N) { NextInFoldingSetBucket = N; }
0149 };
0150
0151
0152 void clear();
0153
0154
0155 unsigned size() const { return NumNodes; }
0156
0157
0158 bool empty() const { return NumNodes == 0; }
0159
0160
0161
0162 unsigned capacity() {
0163
0164
0165 return NumBuckets * 2;
0166 }
0167
0168 protected:
0169
0170
0171
0172 struct FoldingSetInfo {
0173
0174
0175 void (*GetNodeProfile)(const FoldingSetBase *Self, Node *N,
0176 FoldingSetNodeID &ID);
0177
0178
0179
0180 bool (*NodeEquals)(const FoldingSetBase *Self, Node *N,
0181 const FoldingSetNodeID &ID, unsigned IDHash,
0182 FoldingSetNodeID &TempID);
0183
0184
0185
0186 unsigned (*ComputeNodeHash)(const FoldingSetBase *Self, Node *N,
0187 FoldingSetNodeID &TempID);
0188 };
0189
0190 private:
0191
0192 void GrowHashTable(const FoldingSetInfo &Info);
0193
0194
0195
0196
0197 void GrowBucketCount(unsigned NewBucketCount, const FoldingSetInfo &Info);
0198
0199 protected:
0200
0201
0202
0203
0204
0205
0206 void reserve(unsigned EltCount, const FoldingSetInfo &Info);
0207
0208
0209
0210 bool RemoveNode(Node *N);
0211
0212
0213
0214
0215 Node *GetOrInsertNode(Node *N, const FoldingSetInfo &Info);
0216
0217
0218
0219
0220 Node *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos,
0221 const FoldingSetInfo &Info);
0222
0223
0224
0225
0226 void InsertNode(Node *N, void *InsertPos, const FoldingSetInfo &Info);
0227 };
0228
0229
0230
0231
0232
0233 template<typename T> struct DefaultFoldingSetTrait {
0234 static void Profile(const T &X, FoldingSetNodeID &ID) {
0235 X.Profile(ID);
0236 }
0237 static void Profile(T &X, FoldingSetNodeID &ID) {
0238 X.Profile(ID);
0239 }
0240
0241
0242
0243
0244
0245 static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash,
0246 FoldingSetNodeID &TempID);
0247
0248
0249
0250
0251
0252
0253 static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID);
0254 };
0255
0256
0257
0258
0259
0260
0261
0262 template <typename T, typename Enable = void>
0263 struct FoldingSetTrait : public DefaultFoldingSetTrait<T> {};
0264
0265
0266
0267 template<typename T, typename Ctx>
0268 struct DefaultContextualFoldingSetTrait {
0269 static void Profile(T &X, FoldingSetNodeID &ID, Ctx Context) {
0270 X.Profile(ID, Context);
0271 }
0272
0273 static inline bool Equals(T &X, const FoldingSetNodeID &ID, unsigned IDHash,
0274 FoldingSetNodeID &TempID, Ctx Context);
0275 static inline unsigned ComputeHash(T &X, FoldingSetNodeID &TempID,
0276 Ctx Context);
0277 };
0278
0279
0280
0281 template<typename T, typename Ctx> struct ContextualFoldingSetTrait
0282 : public DefaultContextualFoldingSetTrait<T, Ctx> {};
0283
0284
0285
0286
0287
0288
0289
0290 class FoldingSetNodeIDRef {
0291 const unsigned *Data = nullptr;
0292 size_t Size = 0;
0293
0294 public:
0295 FoldingSetNodeIDRef() = default;
0296 FoldingSetNodeIDRef(const unsigned *D, size_t S) : Data(D), Size(S) {}
0297
0298
0299
0300 unsigned ComputeHash() const {
0301 return static_cast<unsigned>(hash_combine_range(Data, Data + Size));
0302 }
0303
0304
0305
0306 unsigned computeStableHash() const {
0307 return static_cast<unsigned>(xxh3_64bits(ArrayRef(
0308 reinterpret_cast<const uint8_t *>(Data), sizeof(unsigned) * Size)));
0309 }
0310
0311 bool operator==(FoldingSetNodeIDRef) const;
0312
0313 bool operator!=(FoldingSetNodeIDRef RHS) const { return !(*this == RHS); }
0314
0315
0316
0317 bool operator<(FoldingSetNodeIDRef) const;
0318
0319 const unsigned *getData() const { return Data; }
0320 size_t getSize() const { return Size; }
0321 };
0322
0323
0324
0325
0326
0327 class FoldingSetNodeID {
0328
0329
0330 SmallVector<unsigned, 32> Bits;
0331
0332 public:
0333 FoldingSetNodeID() = default;
0334
0335 FoldingSetNodeID(FoldingSetNodeIDRef Ref)
0336 : Bits(Ref.getData(), Ref.getData() + Ref.getSize()) {}
0337
0338
0339 void AddPointer(const void *Ptr) {
0340
0341
0342
0343
0344 static_assert(sizeof(uintptr_t) <= sizeof(unsigned long long),
0345 "unexpected pointer size");
0346 AddInteger(reinterpret_cast<uintptr_t>(Ptr));
0347 }
0348 void AddInteger(signed I) { Bits.push_back(I); }
0349 void AddInteger(unsigned I) { Bits.push_back(I); }
0350 void AddInteger(long I) { AddInteger((unsigned long)I); }
0351 void AddInteger(unsigned long I) {
0352 if (sizeof(long) == sizeof(int))
0353 AddInteger(unsigned(I));
0354 else if (sizeof(long) == sizeof(long long)) {
0355 AddInteger((unsigned long long)I);
0356 } else {
0357 llvm_unreachable("unexpected sizeof(long)");
0358 }
0359 }
0360 void AddInteger(long long I) { AddInteger((unsigned long long)I); }
0361 void AddInteger(unsigned long long I) {
0362 AddInteger(unsigned(I));
0363 AddInteger(unsigned(I >> 32));
0364 }
0365
0366 void AddBoolean(bool B) { AddInteger(B ? 1U : 0U); }
0367 void AddString(StringRef String);
0368 void AddNodeID(const FoldingSetNodeID &ID);
0369
0370 template <typename T>
0371 inline void Add(const T &x) { FoldingSetTrait<T>::Profile(x, *this); }
0372
0373
0374
0375 inline void clear() { Bits.clear(); }
0376
0377
0378
0379
0380 unsigned ComputeHash() const {
0381 return FoldingSetNodeIDRef(Bits.data(), Bits.size()).ComputeHash();
0382 }
0383
0384
0385
0386 unsigned computeStableHash() const {
0387 return FoldingSetNodeIDRef(Bits.data(), Bits.size()).computeStableHash();
0388 }
0389
0390
0391 bool operator==(const FoldingSetNodeID &RHS) const;
0392 bool operator==(const FoldingSetNodeIDRef RHS) const;
0393
0394 bool operator!=(const FoldingSetNodeID &RHS) const { return !(*this == RHS); }
0395 bool operator!=(const FoldingSetNodeIDRef RHS) const { return !(*this ==RHS);}
0396
0397
0398
0399 bool operator<(const FoldingSetNodeID &RHS) const;
0400 bool operator<(const FoldingSetNodeIDRef RHS) const;
0401
0402
0403
0404
0405 FoldingSetNodeIDRef Intern(BumpPtrAllocator &Allocator) const;
0406 };
0407
0408
0409 using FoldingSetNode = FoldingSetBase::Node;
0410 template<class T> class FoldingSetIterator;
0411 template<class T> class FoldingSetBucketIterator;
0412
0413
0414
0415 template<typename T>
0416 inline bool
0417 DefaultFoldingSetTrait<T>::Equals(T &X, const FoldingSetNodeID &ID,
0418 unsigned ,
0419 FoldingSetNodeID &TempID) {
0420 FoldingSetTrait<T>::Profile(X, TempID);
0421 return TempID == ID;
0422 }
0423 template<typename T>
0424 inline unsigned
0425 DefaultFoldingSetTrait<T>::ComputeHash(T &X, FoldingSetNodeID &TempID) {
0426 FoldingSetTrait<T>::Profile(X, TempID);
0427 return TempID.ComputeHash();
0428 }
0429 template<typename T, typename Ctx>
0430 inline bool
0431 DefaultContextualFoldingSetTrait<T, Ctx>::Equals(T &X,
0432 const FoldingSetNodeID &ID,
0433 unsigned ,
0434 FoldingSetNodeID &TempID,
0435 Ctx Context) {
0436 ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context);
0437 return TempID == ID;
0438 }
0439 template<typename T, typename Ctx>
0440 inline unsigned
0441 DefaultContextualFoldingSetTrait<T, Ctx>::ComputeHash(T &X,
0442 FoldingSetNodeID &TempID,
0443 Ctx Context) {
0444 ContextualFoldingSetTrait<T, Ctx>::Profile(X, TempID, Context);
0445 return TempID.ComputeHash();
0446 }
0447
0448
0449
0450
0451 template <class Derived, class T> class FoldingSetImpl : public FoldingSetBase {
0452 protected:
0453 explicit FoldingSetImpl(unsigned Log2InitSize)
0454 : FoldingSetBase(Log2InitSize) {}
0455
0456 FoldingSetImpl(FoldingSetImpl &&Arg) = default;
0457 FoldingSetImpl &operator=(FoldingSetImpl &&RHS) = default;
0458 ~FoldingSetImpl() = default;
0459
0460 public:
0461 using iterator = FoldingSetIterator<T>;
0462
0463 iterator begin() { return iterator(Buckets); }
0464 iterator end() { return iterator(Buckets+NumBuckets); }
0465
0466 using const_iterator = FoldingSetIterator<const T>;
0467
0468 const_iterator begin() const { return const_iterator(Buckets); }
0469 const_iterator end() const { return const_iterator(Buckets+NumBuckets); }
0470
0471 using bucket_iterator = FoldingSetBucketIterator<T>;
0472
0473 bucket_iterator bucket_begin(unsigned hash) {
0474 return bucket_iterator(Buckets + (hash & (NumBuckets-1)));
0475 }
0476
0477 bucket_iterator bucket_end(unsigned hash) {
0478 return bucket_iterator(Buckets + (hash & (NumBuckets-1)), true);
0479 }
0480
0481
0482
0483
0484 void reserve(unsigned EltCount) {
0485 return FoldingSetBase::reserve(EltCount, Derived::getFoldingSetInfo());
0486 }
0487
0488
0489
0490 bool RemoveNode(T *N) {
0491 return FoldingSetBase::RemoveNode(N);
0492 }
0493
0494
0495
0496
0497 T *GetOrInsertNode(T *N) {
0498 return static_cast<T *>(
0499 FoldingSetBase::GetOrInsertNode(N, Derived::getFoldingSetInfo()));
0500 }
0501
0502
0503
0504
0505 T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {
0506 return static_cast<T *>(FoldingSetBase::FindNodeOrInsertPos(
0507 ID, InsertPos, Derived::getFoldingSetInfo()));
0508 }
0509
0510
0511
0512
0513 void InsertNode(T *N, void *InsertPos) {
0514 FoldingSetBase::InsertNode(N, InsertPos, Derived::getFoldingSetInfo());
0515 }
0516
0517
0518
0519 void InsertNode(T *N) {
0520 T *Inserted = GetOrInsertNode(N);
0521 (void)Inserted;
0522 assert(Inserted == N && "Node already inserted!");
0523 }
0524 };
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535 template <class T>
0536 class FoldingSet : public FoldingSetImpl<FoldingSet<T>, T> {
0537 using Super = FoldingSetImpl<FoldingSet, T>;
0538 using Node = typename Super::Node;
0539
0540
0541
0542 static void GetNodeProfile(const FoldingSetBase *, Node *N,
0543 FoldingSetNodeID &ID) {
0544 T *TN = static_cast<T *>(N);
0545 FoldingSetTrait<T>::Profile(*TN, ID);
0546 }
0547
0548
0549
0550 static bool NodeEquals(const FoldingSetBase *, Node *N,
0551 const FoldingSetNodeID &ID, unsigned IDHash,
0552 FoldingSetNodeID &TempID) {
0553 T *TN = static_cast<T *>(N);
0554 return FoldingSetTrait<T>::Equals(*TN, ID, IDHash, TempID);
0555 }
0556
0557
0558
0559 static unsigned ComputeNodeHash(const FoldingSetBase *, Node *N,
0560 FoldingSetNodeID &TempID) {
0561 T *TN = static_cast<T *>(N);
0562 return FoldingSetTrait<T>::ComputeHash(*TN, TempID);
0563 }
0564
0565 static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo() {
0566 static constexpr FoldingSetBase::FoldingSetInfo Info = {
0567 GetNodeProfile, NodeEquals, ComputeNodeHash};
0568 return Info;
0569 }
0570 friend Super;
0571
0572 public:
0573 explicit FoldingSet(unsigned Log2InitSize = 6) : Super(Log2InitSize) {}
0574 FoldingSet(FoldingSet &&Arg) = default;
0575 FoldingSet &operator=(FoldingSet &&RHS) = default;
0576 };
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587 template <class T, class Ctx>
0588 class ContextualFoldingSet
0589 : public FoldingSetImpl<ContextualFoldingSet<T, Ctx>, T> {
0590
0591
0592
0593
0594
0595 using Super = FoldingSetImpl<ContextualFoldingSet, T>;
0596 using Node = typename Super::Node;
0597
0598 Ctx Context;
0599
0600 static const Ctx &getContext(const FoldingSetBase *Base) {
0601 return static_cast<const ContextualFoldingSet*>(Base)->Context;
0602 }
0603
0604
0605
0606 static void GetNodeProfile(const FoldingSetBase *Base, Node *N,
0607 FoldingSetNodeID &ID) {
0608 T *TN = static_cast<T *>(N);
0609 ContextualFoldingSetTrait<T, Ctx>::Profile(*TN, ID, getContext(Base));
0610 }
0611
0612 static bool NodeEquals(const FoldingSetBase *Base, Node *N,
0613 const FoldingSetNodeID &ID, unsigned IDHash,
0614 FoldingSetNodeID &TempID) {
0615 T *TN = static_cast<T *>(N);
0616 return ContextualFoldingSetTrait<T, Ctx>::Equals(*TN, ID, IDHash, TempID,
0617 getContext(Base));
0618 }
0619
0620 static unsigned ComputeNodeHash(const FoldingSetBase *Base, Node *N,
0621 FoldingSetNodeID &TempID) {
0622 T *TN = static_cast<T *>(N);
0623 return ContextualFoldingSetTrait<T, Ctx>::ComputeHash(*TN, TempID,
0624 getContext(Base));
0625 }
0626
0627 static const FoldingSetBase::FoldingSetInfo &getFoldingSetInfo() {
0628 static constexpr FoldingSetBase::FoldingSetInfo Info = {
0629 GetNodeProfile, NodeEquals, ComputeNodeHash};
0630 return Info;
0631 }
0632 friend Super;
0633
0634 public:
0635 explicit ContextualFoldingSet(Ctx Context, unsigned Log2InitSize = 6)
0636 : Super(Log2InitSize), Context(Context) {}
0637
0638 Ctx getContext() const { return Context; }
0639 };
0640
0641
0642
0643
0644
0645
0646 template <class T, class VectorT = SmallVector<T*, 8>>
0647 class FoldingSetVector {
0648 FoldingSet<T> Set;
0649 VectorT Vector;
0650
0651 public:
0652 explicit FoldingSetVector(unsigned Log2InitSize = 6) : Set(Log2InitSize) {}
0653
0654 using iterator = pointee_iterator<typename VectorT::iterator>;
0655
0656 iterator begin() { return Vector.begin(); }
0657 iterator end() { return Vector.end(); }
0658
0659 using const_iterator = pointee_iterator<typename VectorT::const_iterator>;
0660
0661 const_iterator begin() const { return Vector.begin(); }
0662 const_iterator end() const { return Vector.end(); }
0663
0664
0665 void clear() { Set.clear(); Vector.clear(); }
0666
0667
0668
0669
0670 T *FindNodeOrInsertPos(const FoldingSetNodeID &ID, void *&InsertPos) {
0671 return Set.FindNodeOrInsertPos(ID, InsertPos);
0672 }
0673
0674
0675
0676
0677 T *GetOrInsertNode(T *N) {
0678 T *Result = Set.GetOrInsertNode(N);
0679 if (Result == N) Vector.push_back(N);
0680 return Result;
0681 }
0682
0683
0684
0685
0686 void InsertNode(T *N, void *InsertPos) {
0687 Set.InsertNode(N, InsertPos);
0688 Vector.push_back(N);
0689 }
0690
0691
0692
0693 void InsertNode(T *N) {
0694 Set.InsertNode(N);
0695 Vector.push_back(N);
0696 }
0697
0698
0699 unsigned size() const { return Set.size(); }
0700
0701
0702 bool empty() const { return Set.empty(); }
0703 };
0704
0705
0706
0707
0708 class FoldingSetIteratorImpl {
0709 protected:
0710 FoldingSetNode *NodePtr;
0711
0712 FoldingSetIteratorImpl(void **Bucket);
0713
0714 void advance();
0715
0716 public:
0717 bool operator==(const FoldingSetIteratorImpl &RHS) const {
0718 return NodePtr == RHS.NodePtr;
0719 }
0720 bool operator!=(const FoldingSetIteratorImpl &RHS) const {
0721 return NodePtr != RHS.NodePtr;
0722 }
0723 };
0724
0725 template <class T> class FoldingSetIterator : public FoldingSetIteratorImpl {
0726 public:
0727 explicit FoldingSetIterator(void **Bucket) : FoldingSetIteratorImpl(Bucket) {}
0728
0729 T &operator*() const {
0730 return *static_cast<T*>(NodePtr);
0731 }
0732
0733 T *operator->() const {
0734 return static_cast<T*>(NodePtr);
0735 }
0736
0737 inline FoldingSetIterator &operator++() {
0738 advance();
0739 return *this;
0740 }
0741 FoldingSetIterator operator++(int) {
0742 FoldingSetIterator tmp = *this; ++*this; return tmp;
0743 }
0744 };
0745
0746
0747
0748
0749
0750 class FoldingSetBucketIteratorImpl {
0751 protected:
0752 void *Ptr;
0753
0754 explicit FoldingSetBucketIteratorImpl(void **Bucket);
0755
0756 FoldingSetBucketIteratorImpl(void **Bucket, bool) : Ptr(Bucket) {}
0757
0758 void advance() {
0759 void *Probe = static_cast<FoldingSetNode*>(Ptr)->getNextInBucket();
0760 uintptr_t x = reinterpret_cast<uintptr_t>(Probe) & ~0x1;
0761 Ptr = reinterpret_cast<void*>(x);
0762 }
0763
0764 public:
0765 bool operator==(const FoldingSetBucketIteratorImpl &RHS) const {
0766 return Ptr == RHS.Ptr;
0767 }
0768 bool operator!=(const FoldingSetBucketIteratorImpl &RHS) const {
0769 return Ptr != RHS.Ptr;
0770 }
0771 };
0772
0773 template <class T>
0774 class FoldingSetBucketIterator : public FoldingSetBucketIteratorImpl {
0775 public:
0776 explicit FoldingSetBucketIterator(void **Bucket) :
0777 FoldingSetBucketIteratorImpl(Bucket) {}
0778
0779 FoldingSetBucketIterator(void **Bucket, bool) :
0780 FoldingSetBucketIteratorImpl(Bucket, true) {}
0781
0782 T &operator*() const { return *static_cast<T*>(Ptr); }
0783 T *operator->() const { return static_cast<T*>(Ptr); }
0784
0785 inline FoldingSetBucketIterator &operator++() {
0786 advance();
0787 return *this;
0788 }
0789 FoldingSetBucketIterator operator++(int) {
0790 FoldingSetBucketIterator tmp = *this; ++*this; return tmp;
0791 }
0792 };
0793
0794
0795
0796
0797 template <typename T>
0798 class FoldingSetNodeWrapper : public FoldingSetNode {
0799 T data;
0800
0801 public:
0802 template <typename... Ts>
0803 explicit FoldingSetNodeWrapper(Ts &&... Args)
0804 : data(std::forward<Ts>(Args)...) {}
0805
0806 void Profile(FoldingSetNodeID &ID) { FoldingSetTrait<T>::Profile(data, ID); }
0807
0808 T &getValue() { return data; }
0809 const T &getValue() const { return data; }
0810
0811 operator T&() { return data; }
0812 operator const T&() const { return data; }
0813 };
0814
0815
0816
0817
0818
0819
0820
0821 class FastFoldingSetNode : public FoldingSetNode {
0822 FoldingSetNodeID FastID;
0823
0824 protected:
0825 explicit FastFoldingSetNode(const FoldingSetNodeID &ID) : FastID(ID) {}
0826
0827 public:
0828 void Profile(FoldingSetNodeID &ID) const { ID.AddNodeID(FastID); }
0829 };
0830
0831
0832
0833
0834 template<typename T> struct FoldingSetTrait<T*> {
0835 static inline void Profile(T *X, FoldingSetNodeID &ID) {
0836 ID.AddPointer(X);
0837 }
0838 };
0839 template <typename T1, typename T2>
0840 struct FoldingSetTrait<std::pair<T1, T2>> {
0841 static inline void Profile(const std::pair<T1, T2> &P,
0842 FoldingSetNodeID &ID) {
0843 ID.Add(P.first);
0844 ID.Add(P.second);
0845 }
0846 };
0847
0848 template <typename T>
0849 struct FoldingSetTrait<T, std::enable_if_t<std::is_enum<T>::value>> {
0850 static void Profile(const T &X, FoldingSetNodeID &ID) {
0851 ID.AddInteger(llvm::to_underlying(X));
0852 }
0853 };
0854
0855 }
0856
0857 #endif