File indexing completed on 2026-05-10 08:43:08
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef LLVM_ADT_SMALLPTRSET_H
0016 #define LLVM_ADT_SMALLPTRSET_H
0017
0018 #include "llvm/ADT/EpochTracker.h"
0019 #include "llvm/Support/MathExtras.h"
0020 #include "llvm/Support/ReverseIteration.h"
0021 #include "llvm/Support/type_traits.h"
0022 #include <algorithm>
0023 #include <cassert>
0024 #include <cstddef>
0025 #include <cstdlib>
0026 #include <cstring>
0027 #include <initializer_list>
0028 #include <iterator>
0029 #include <limits>
0030 #include <utility>
0031
0032 namespace llvm {
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 class SmallPtrSetImplBase : public DebugEpochBase {
0053 friend class SmallPtrSetIteratorImpl;
0054
0055 protected:
0056
0057 const void **CurArray;
0058
0059 unsigned CurArraySize;
0060
0061
0062
0063
0064 unsigned NumNonEmpty;
0065
0066 unsigned NumTombstones;
0067
0068 bool IsSmall;
0069
0070
0071 SmallPtrSetImplBase(const void **SmallStorage,
0072 const SmallPtrSetImplBase &that);
0073 SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
0074 const void **RHSSmallStorage, SmallPtrSetImplBase &&that);
0075
0076 explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize)
0077 : CurArray(SmallStorage), CurArraySize(SmallSize), NumNonEmpty(0),
0078 NumTombstones(0), IsSmall(true) {
0079 assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
0080 "Initial size must be a power of two!");
0081 }
0082
0083 ~SmallPtrSetImplBase() {
0084 if (!isSmall())
0085 free(CurArray);
0086 }
0087
0088 public:
0089 using size_type = unsigned;
0090
0091 SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
0092
0093 [[nodiscard]] bool empty() const { return size() == 0; }
0094 size_type size() const { return NumNonEmpty - NumTombstones; }
0095 size_type capacity() const { return CurArraySize; }
0096
0097 void clear() {
0098 incrementEpoch();
0099
0100
0101 if (!isSmall()) {
0102 if (size() * 4 < CurArraySize && CurArraySize > 32)
0103 return shrink_and_clear();
0104
0105 memset(CurArray, -1, CurArraySize * sizeof(void *));
0106 }
0107
0108 NumNonEmpty = 0;
0109 NumTombstones = 0;
0110 }
0111
0112 void reserve(size_type NumEntries) {
0113 incrementEpoch();
0114
0115 if (NumEntries == 0)
0116 return;
0117
0118 if (isSmall() && NumEntries <= CurArraySize)
0119 return;
0120
0121
0122 if (!isSmall() && ((NumEntries - 1) * 4) < (CurArraySize * 3))
0123 return;
0124
0125
0126 size_type NewSize = NumEntries + (NumEntries / 3);
0127 NewSize = 1 << (Log2_32_Ceil(NewSize) + 1);
0128
0129 NewSize = std::max(128u, NewSize);
0130 Grow(NewSize);
0131 }
0132
0133 protected:
0134 static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); }
0135
0136 static void *getEmptyMarker() {
0137
0138
0139 return reinterpret_cast<void*>(-1);
0140 }
0141
0142 const void **EndPointer() const {
0143 return isSmall() ? CurArray + NumNonEmpty : CurArray + CurArraySize;
0144 }
0145
0146
0147
0148
0149 std::pair<const void *const *, bool> insert_imp(const void *Ptr) {
0150 if (isSmall()) {
0151
0152 for (const void **APtr = CurArray, **E = CurArray + NumNonEmpty;
0153 APtr != E; ++APtr) {
0154 const void *Value = *APtr;
0155 if (Value == Ptr)
0156 return std::make_pair(APtr, false);
0157 }
0158
0159
0160 if (NumNonEmpty < CurArraySize) {
0161 CurArray[NumNonEmpty++] = Ptr;
0162 incrementEpoch();
0163 return std::make_pair(CurArray + (NumNonEmpty - 1), true);
0164 }
0165
0166 }
0167 return insert_imp_big(Ptr);
0168 }
0169
0170
0171
0172
0173
0174 bool erase_imp(const void * Ptr) {
0175 if (isSmall()) {
0176 for (const void **APtr = CurArray, **E = CurArray + NumNonEmpty;
0177 APtr != E; ++APtr) {
0178 if (*APtr == Ptr) {
0179 *APtr = CurArray[--NumNonEmpty];
0180 incrementEpoch();
0181 return true;
0182 }
0183 }
0184 return false;
0185 }
0186
0187 auto *Bucket = doFind(Ptr);
0188 if (!Bucket)
0189 return false;
0190
0191 *const_cast<const void **>(Bucket) = getTombstoneMarker();
0192 NumTombstones++;
0193
0194
0195 incrementEpoch();
0196 return true;
0197 }
0198
0199
0200
0201
0202 const void *const * find_imp(const void * Ptr) const {
0203 if (isSmall()) {
0204
0205 for (const void *const *APtr = CurArray, *const *E =
0206 CurArray + NumNonEmpty;
0207 APtr != E; ++APtr)
0208 if (*APtr == Ptr)
0209 return APtr;
0210 return EndPointer();
0211 }
0212
0213
0214 if (auto *Bucket = doFind(Ptr))
0215 return Bucket;
0216 return EndPointer();
0217 }
0218
0219 bool contains_imp(const void *Ptr) const {
0220 if (isSmall()) {
0221
0222 const void *const *APtr = CurArray;
0223 const void *const *E = CurArray + NumNonEmpty;
0224 for (; APtr != E; ++APtr)
0225 if (*APtr == Ptr)
0226 return true;
0227 return false;
0228 }
0229
0230 return doFind(Ptr) != nullptr;
0231 }
0232
0233 bool isSmall() const { return IsSmall; }
0234
0235 private:
0236 std::pair<const void *const *, bool> insert_imp_big(const void *Ptr);
0237
0238 const void *const *doFind(const void *Ptr) const;
0239 const void * const *FindBucketFor(const void *Ptr) const;
0240 void shrink_and_clear();
0241
0242
0243 void Grow(unsigned NewSize);
0244
0245 protected:
0246
0247
0248 void swap(const void **SmallStorage, const void **RHSSmallStorage,
0249 SmallPtrSetImplBase &RHS);
0250
0251 void copyFrom(const void **SmallStorage, const SmallPtrSetImplBase &RHS);
0252 void moveFrom(const void **SmallStorage, unsigned SmallSize,
0253 const void **RHSSmallStorage, SmallPtrSetImplBase &&RHS);
0254
0255 private:
0256
0257 void moveHelper(const void **SmallStorage, unsigned SmallSize,
0258 const void **RHSSmallStorage, SmallPtrSetImplBase &&RHS);
0259
0260 void copyHelper(const SmallPtrSetImplBase &RHS);
0261 };
0262
0263
0264
0265 class SmallPtrSetIteratorImpl {
0266 protected:
0267 const void *const *Bucket;
0268 const void *const *End;
0269
0270 public:
0271 explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
0272 : Bucket(BP), End(E) {
0273 if (shouldReverseIterate()) {
0274 RetreatIfNotValid();
0275 return;
0276 }
0277 AdvanceIfNotValid();
0278 }
0279
0280 bool operator==(const SmallPtrSetIteratorImpl &RHS) const {
0281 return Bucket == RHS.Bucket;
0282 }
0283 bool operator!=(const SmallPtrSetIteratorImpl &RHS) const {
0284 return Bucket != RHS.Bucket;
0285 }
0286
0287 protected:
0288
0289
0290
0291 void AdvanceIfNotValid() {
0292 assert(Bucket <= End);
0293 while (Bucket != End &&
0294 (*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
0295 *Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
0296 ++Bucket;
0297 }
0298 void RetreatIfNotValid() {
0299 assert(Bucket >= End);
0300 while (Bucket != End &&
0301 (Bucket[-1] == SmallPtrSetImplBase::getEmptyMarker() ||
0302 Bucket[-1] == SmallPtrSetImplBase::getTombstoneMarker())) {
0303 --Bucket;
0304 }
0305 }
0306 };
0307
0308
0309 template <typename PtrTy>
0310 class LLVM_DEBUGEPOCHBASE_HANDLEBASE_EMPTYBASE SmallPtrSetIterator
0311 : public SmallPtrSetIteratorImpl,
0312 DebugEpochBase::HandleBase {
0313 using PtrTraits = PointerLikeTypeTraits<PtrTy>;
0314
0315 public:
0316 using value_type = PtrTy;
0317 using reference = PtrTy;
0318 using pointer = PtrTy;
0319 using difference_type = std::ptrdiff_t;
0320 using iterator_category = std::forward_iterator_tag;
0321
0322 explicit SmallPtrSetIterator(const void *const *BP, const void *const *E,
0323 const DebugEpochBase &Epoch)
0324 : SmallPtrSetIteratorImpl(BP, E), DebugEpochBase::HandleBase(&Epoch) {}
0325
0326
0327
0328 const PtrTy operator*() const {
0329 assert(isHandleInSync() && "invalid iterator access!");
0330 if (shouldReverseIterate()) {
0331 assert(Bucket > End);
0332 return PtrTraits::getFromVoidPointer(const_cast<void *>(Bucket[-1]));
0333 }
0334 assert(Bucket < End);
0335 return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket));
0336 }
0337
0338 inline SmallPtrSetIterator& operator++() {
0339 assert(isHandleInSync() && "invalid iterator access!");
0340 if (shouldReverseIterate()) {
0341 --Bucket;
0342 RetreatIfNotValid();
0343 return *this;
0344 }
0345 ++Bucket;
0346 AdvanceIfNotValid();
0347 return *this;
0348 }
0349
0350 SmallPtrSetIterator operator++(int) {
0351 SmallPtrSetIterator tmp = *this;
0352 ++*this;
0353 return tmp;
0354 }
0355 };
0356
0357
0358
0359
0360
0361
0362 template <typename PtrType>
0363 class SmallPtrSetImpl : public SmallPtrSetImplBase {
0364 using ConstPtrType = typename add_const_past_pointer<PtrType>::type;
0365 using PtrTraits = PointerLikeTypeTraits<PtrType>;
0366 using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
0367
0368 protected:
0369
0370 using SmallPtrSetImplBase::SmallPtrSetImplBase;
0371
0372 public:
0373 using iterator = SmallPtrSetIterator<PtrType>;
0374 using const_iterator = SmallPtrSetIterator<PtrType>;
0375 using key_type = ConstPtrType;
0376 using value_type = PtrType;
0377
0378 SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
0379
0380
0381
0382
0383
0384 std::pair<iterator, bool> insert(PtrType Ptr) {
0385 auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr));
0386 return std::make_pair(makeIterator(p.first), p.second);
0387 }
0388
0389
0390
0391
0392 iterator insert(iterator, PtrType Ptr) {
0393 return insert(Ptr).first;
0394 }
0395
0396
0397
0398
0399
0400
0401 bool erase(PtrType Ptr) {
0402 return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
0403 }
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417 template <typename UnaryPredicate>
0418 bool remove_if(UnaryPredicate P) {
0419 bool Removed = false;
0420 if (isSmall()) {
0421 const void **APtr = CurArray, **E = CurArray + NumNonEmpty;
0422 while (APtr != E) {
0423 PtrType Ptr = PtrTraits::getFromVoidPointer(const_cast<void *>(*APtr));
0424 if (P(Ptr)) {
0425 *APtr = *--E;
0426 --NumNonEmpty;
0427 incrementEpoch();
0428 Removed = true;
0429 } else {
0430 ++APtr;
0431 }
0432 }
0433 return Removed;
0434 }
0435
0436 for (const void **APtr = CurArray, **E = EndPointer(); APtr != E; ++APtr) {
0437 const void *Value = *APtr;
0438 if (Value == getTombstoneMarker() || Value == getEmptyMarker())
0439 continue;
0440 PtrType Ptr = PtrTraits::getFromVoidPointer(const_cast<void *>(Value));
0441 if (P(Ptr)) {
0442 *APtr = getTombstoneMarker();
0443 ++NumTombstones;
0444 incrementEpoch();
0445 Removed = true;
0446 }
0447 }
0448 return Removed;
0449 }
0450
0451
0452 size_type count(ConstPtrType Ptr) const {
0453 return contains_imp(ConstPtrTraits::getAsVoidPointer(Ptr));
0454 }
0455 iterator find(ConstPtrType Ptr) const {
0456 return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)));
0457 }
0458 bool contains(ConstPtrType Ptr) const {
0459 return contains_imp(ConstPtrTraits::getAsVoidPointer(Ptr));
0460 }
0461
0462 template <typename IterT>
0463 void insert(IterT I, IterT E) {
0464 for (; I != E; ++I)
0465 insert(*I);
0466 }
0467
0468 void insert(std::initializer_list<PtrType> IL) {
0469 insert(IL.begin(), IL.end());
0470 }
0471
0472 iterator begin() const {
0473 if (shouldReverseIterate())
0474 return makeIterator(EndPointer() - 1);
0475 return makeIterator(CurArray);
0476 }
0477 iterator end() const { return makeIterator(EndPointer()); }
0478
0479 private:
0480
0481 iterator makeIterator(const void *const *P) const {
0482 if (shouldReverseIterate())
0483 return iterator(P == EndPointer() ? CurArray : P + 1, CurArray, *this);
0484 return iterator(P, EndPointer(), *this);
0485 }
0486 };
0487
0488
0489
0490
0491
0492 template <typename PtrType>
0493 bool operator==(const SmallPtrSetImpl<PtrType> &LHS,
0494 const SmallPtrSetImpl<PtrType> &RHS) {
0495 if (LHS.size() != RHS.size())
0496 return false;
0497
0498 for (const auto *KV : LHS)
0499 if (!RHS.count(KV))
0500 return false;
0501
0502 return true;
0503 }
0504
0505
0506
0507
0508 template <typename PtrType>
0509 bool operator!=(const SmallPtrSetImpl<PtrType> &LHS,
0510 const SmallPtrSetImpl<PtrType> &RHS) {
0511 return !(LHS == RHS);
0512 }
0513
0514
0515
0516
0517
0518 template<class PtrType, unsigned SmallSize>
0519 class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
0520
0521
0522
0523 static_assert(SmallSize <= 32, "SmallSize should be small");
0524
0525 using BaseT = SmallPtrSetImpl<PtrType>;
0526
0527
0528
0529 static constexpr size_t RoundUpToPowerOfTwo(size_t X) {
0530 size_t C = 1;
0531 size_t CMax = C << (std::numeric_limits<size_t>::digits - 1);
0532 while (C < X && C < CMax)
0533 C <<= 1;
0534 return C;
0535 }
0536
0537
0538 static constexpr size_t SmallSizePowTwo = RoundUpToPowerOfTwo(SmallSize);
0539
0540 const void *SmallStorage[SmallSizePowTwo];
0541
0542 public:
0543 SmallPtrSet() : BaseT(SmallStorage, SmallSizePowTwo) {}
0544 SmallPtrSet(const SmallPtrSet &that) : BaseT(SmallStorage, that) {}
0545 SmallPtrSet(SmallPtrSet &&that)
0546 : BaseT(SmallStorage, SmallSizePowTwo, that.SmallStorage,
0547 std::move(that)) {}
0548
0549 template<typename It>
0550 SmallPtrSet(It I, It E) : BaseT(SmallStorage, SmallSizePowTwo) {
0551 this->insert(I, E);
0552 }
0553
0554 SmallPtrSet(std::initializer_list<PtrType> IL)
0555 : BaseT(SmallStorage, SmallSizePowTwo) {
0556 this->insert(IL.begin(), IL.end());
0557 }
0558
0559 SmallPtrSet<PtrType, SmallSize> &
0560 operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
0561 if (&RHS != this)
0562 this->copyFrom(SmallStorage, RHS);
0563 return *this;
0564 }
0565
0566 SmallPtrSet<PtrType, SmallSize> &
0567 operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
0568 if (&RHS != this)
0569 this->moveFrom(SmallStorage, SmallSizePowTwo, RHS.SmallStorage,
0570 std::move(RHS));
0571 return *this;
0572 }
0573
0574 SmallPtrSet<PtrType, SmallSize> &
0575 operator=(std::initializer_list<PtrType> IL) {
0576 this->clear();
0577 this->insert(IL.begin(), IL.end());
0578 return *this;
0579 }
0580
0581
0582 void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
0583 SmallPtrSetImplBase::swap(SmallStorage, RHS.SmallStorage, RHS);
0584 }
0585 };
0586
0587 }
0588
0589 namespace std {
0590
0591
0592 template<class T, unsigned N>
0593 inline void swap(llvm::SmallPtrSet<T, N> &LHS, llvm::SmallPtrSet<T, N> &RHS) {
0594 LHS.swap(RHS);
0595 }
0596
0597 }
0598
0599 #endif