Home | History | Annotate | Download | only in ADT
      1 //===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file defines the SmallPtrSet class.  See the doxygen comment for
     11 // SmallPtrSetImplBase for more details on the algorithm used.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef LLVM_ADT_SMALLPTRSET_H
     16 #define LLVM_ADT_SMALLPTRSET_H
     17 
     18 #include "llvm/Config/abi-breaking.h"
     19 #include "llvm/Support/Compiler.h"
     20 #include "llvm/Support/PointerLikeTypeTraits.h"
     21 #include "llvm/Support/type_traits.h"
     22 #include <cassert>
     23 #include <cstddef>
     24 #include <cstdlib>
     25 #include <cstring>
     26 #include <initializer_list>
     27 #include <iterator>
     28 #include <utility>
     29 
     30 namespace llvm {
     31 
     32 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
     33 template <class T = void> struct ReverseIterate { static bool value; };
     34 #if LLVM_ENABLE_REVERSE_ITERATION
     35 template <class T> bool ReverseIterate<T>::value = true;
     36 #else
     37 template <class T> bool ReverseIterate<T>::value = false;
     38 #endif
     39 #endif
     40 
     41 /// SmallPtrSetImplBase - This is the common code shared among all the
     42 /// SmallPtrSet<>'s, which is almost everything.  SmallPtrSet has two modes, one
     43 /// for small and one for large sets.
     44 ///
     45 /// Small sets use an array of pointers allocated in the SmallPtrSet object,
     46 /// which is treated as a simple array of pointers.  When a pointer is added to
     47 /// the set, the array is scanned to see if the element already exists, if not
     48 /// the element is 'pushed back' onto the array.  If we run out of space in the
     49 /// array, we grow into the 'large set' case.  SmallSet should be used when the
     50 /// sets are often small.  In this case, no memory allocation is used, and only
     51 /// light-weight and cache-efficient scanning is used.
     52 ///
     53 /// Large sets use a classic exponentially-probed hash table.  Empty buckets are
     54 /// represented with an illegal pointer value (-1) to allow null pointers to be
     55 /// inserted.  Tombstones are represented with another illegal pointer value
     56 /// (-2), to allow deletion.  The hash table is resized when the table is 3/4 or
     57 /// more.  When this happens, the table is doubled in size.
     58 ///
     59 class SmallPtrSetImplBase {
     60   friend class SmallPtrSetIteratorImpl;
     61 
     62 protected:
     63   /// SmallArray - Points to a fixed size set of buckets, used in 'small mode'.
     64   const void **SmallArray;
     65   /// CurArray - This is the current set of buckets.  If equal to SmallArray,
     66   /// then the set is in 'small mode'.
     67   const void **CurArray;
     68   /// CurArraySize - The allocated size of CurArray, always a power of two.
     69   unsigned CurArraySize;
     70 
     71   /// Number of elements in CurArray that contain a value or are a tombstone.
     72   /// If small, all these elements are at the beginning of CurArray and the rest
     73   /// is uninitialized.
     74   unsigned NumNonEmpty;
     75   /// Number of tombstones in CurArray.
     76   unsigned NumTombstones;
     77 
     78   // Helpers to copy and move construct a SmallPtrSet.
     79   SmallPtrSetImplBase(const void **SmallStorage,
     80                       const SmallPtrSetImplBase &that);
     81   SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
     82                       SmallPtrSetImplBase &&that);
     83 
     84   explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize)
     85       : SmallArray(SmallStorage), CurArray(SmallStorage),
     86         CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) {
     87     assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
     88            "Initial size must be a power of two!");
     89   }
     90 
     91   ~SmallPtrSetImplBase() {
     92     if (!isSmall())
     93       free(CurArray);
     94   }
     95 
     96 public:
     97   using size_type = unsigned;
     98 
     99   SmallPtrSetImplBase &operator=(const SmallPtrSetImplBase &) = delete;
    100 
    101   LLVM_NODISCARD bool empty() const { return size() == 0; }
    102   size_type size() const { return NumNonEmpty - NumTombstones; }
    103 
    104   void clear() {
    105     // If the capacity of the array is huge, and the # elements used is small,
    106     // shrink the array.
    107     if (!isSmall()) {
    108       if (size() * 4 < CurArraySize && CurArraySize > 32)
    109         return shrink_and_clear();
    110       // Fill the array with empty markers.
    111       memset(CurArray, -1, CurArraySize * sizeof(void *));
    112     }
    113 
    114     NumNonEmpty = 0;
    115     NumTombstones = 0;
    116   }
    117 
    118 protected:
    119   static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); }
    120 
    121   static void *getEmptyMarker() {
    122     // Note that -1 is chosen to make clear() efficiently implementable with
    123     // memset and because it's not a valid pointer value.
    124     return reinterpret_cast<void*>(-1);
    125   }
    126 
    127   const void **EndPointer() const {
    128     return isSmall() ? CurArray + NumNonEmpty : CurArray + CurArraySize;
    129   }
    130 
    131   /// insert_imp - This returns true if the pointer was new to the set, false if
    132   /// it was already in the set.  This is hidden from the client so that the
    133   /// derived class can check that the right type of pointer is passed in.
    134   std::pair<const void *const *, bool> insert_imp(const void *Ptr) {
    135     if (isSmall()) {
    136       // Check to see if it is already in the set.
    137       const void **LastTombstone = nullptr;
    138       for (const void **APtr = SmallArray, **E = SmallArray + NumNonEmpty;
    139            APtr != E; ++APtr) {
    140         const void *Value = *APtr;
    141         if (Value == Ptr)
    142           return std::make_pair(APtr, false);
    143         if (Value == getTombstoneMarker())
    144           LastTombstone = APtr;
    145       }
    146 
    147       // Did we find any tombstone marker?
    148       if (LastTombstone != nullptr) {
    149         *LastTombstone = Ptr;
    150         --NumTombstones;
    151         return std::make_pair(LastTombstone, true);
    152       }
    153 
    154       // Nope, there isn't.  If we stay small, just 'pushback' now.
    155       if (NumNonEmpty < CurArraySize) {
    156         SmallArray[NumNonEmpty++] = Ptr;
    157         return std::make_pair(SmallArray + (NumNonEmpty - 1), true);
    158       }
    159       // Otherwise, hit the big set case, which will call grow.
    160     }
    161     return insert_imp_big(Ptr);
    162   }
    163 
    164   /// erase_imp - If the set contains the specified pointer, remove it and
    165   /// return true, otherwise return false.  This is hidden from the client so
    166   /// that the derived class can check that the right type of pointer is passed
    167   /// in.
    168   bool erase_imp(const void * Ptr) {
    169     const void *const *P = find_imp(Ptr);
    170     if (P == EndPointer())
    171       return false;
    172 
    173     const void **Loc = const_cast<const void **>(P);
    174     assert(*Loc == Ptr && "broken find!");
    175     *Loc = getTombstoneMarker();
    176     NumTombstones++;
    177     return true;
    178   }
    179 
    180   /// Returns the raw pointer needed to construct an iterator.  If element not
    181   /// found, this will be EndPointer.  Otherwise, it will be a pointer to the
    182   /// slot which stores Ptr;
    183   const void *const * find_imp(const void * Ptr) const {
    184     if (isSmall()) {
    185       // Linear search for the item.
    186       for (const void *const *APtr = SmallArray,
    187                       *const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr)
    188         if (*APtr == Ptr)
    189           return APtr;
    190       return EndPointer();
    191     }
    192 
    193     // Big set case.
    194     auto *Bucket = FindBucketFor(Ptr);
    195     if (*Bucket == Ptr)
    196       return Bucket;
    197     return EndPointer();
    198   }
    199 
    200 private:
    201   bool isSmall() const { return CurArray == SmallArray; }
    202 
    203   std::pair<const void *const *, bool> insert_imp_big(const void *Ptr);
    204 
    205   const void * const *FindBucketFor(const void *Ptr) const;
    206   void shrink_and_clear();
    207 
    208   /// Grow - Allocate a larger backing store for the buckets and move it over.
    209   void Grow(unsigned NewSize);
    210 
    211 protected:
    212   /// swap - Swaps the elements of two sets.
    213   /// Note: This method assumes that both sets have the same small size.
    214   void swap(SmallPtrSetImplBase &RHS);
    215 
    216   void CopyFrom(const SmallPtrSetImplBase &RHS);
    217   void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
    218 
    219 private:
    220   /// Code shared by MoveFrom() and move constructor.
    221   void MoveHelper(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
    222   /// Code shared by CopyFrom() and copy constructor.
    223   void CopyHelper(const SmallPtrSetImplBase &RHS);
    224 };
    225 
    226 /// SmallPtrSetIteratorImpl - This is the common base class shared between all
    227 /// instances of SmallPtrSetIterator.
    228 class SmallPtrSetIteratorImpl {
    229 protected:
    230   const void *const *Bucket;
    231   const void *const *End;
    232 
    233 public:
    234   explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
    235     : Bucket(BP), End(E) {
    236 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
    237     if (ReverseIterate<bool>::value) {
    238       RetreatIfNotValid();
    239       return;
    240     }
    241 #endif
    242     AdvanceIfNotValid();
    243   }
    244 
    245   bool operator==(const SmallPtrSetIteratorImpl &RHS) const {
    246     return Bucket == RHS.Bucket;
    247   }
    248   bool operator!=(const SmallPtrSetIteratorImpl &RHS) const {
    249     return Bucket != RHS.Bucket;
    250   }
    251 
    252 protected:
    253   /// AdvanceIfNotValid - If the current bucket isn't valid, advance to a bucket
    254   /// that is.   This is guaranteed to stop because the end() bucket is marked
    255   /// valid.
    256   void AdvanceIfNotValid() {
    257     assert(Bucket <= End);
    258     while (Bucket != End &&
    259            (*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
    260             *Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
    261       ++Bucket;
    262   }
    263 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
    264   void RetreatIfNotValid() {
    265     assert(Bucket >= End);
    266     while (Bucket != End &&
    267            (Bucket[-1] == SmallPtrSetImplBase::getEmptyMarker() ||
    268             Bucket[-1] == SmallPtrSetImplBase::getTombstoneMarker())) {
    269       --Bucket;
    270     }
    271   }
    272 #endif
    273 };
    274 
    275 /// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
    276 template<typename PtrTy>
    277 class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
    278   using PtrTraits = PointerLikeTypeTraits<PtrTy>;
    279 
    280 public:
    281   using value_type = PtrTy;
    282   using reference = PtrTy;
    283   using pointer = PtrTy;
    284   using difference_type = std::ptrdiff_t;
    285   using iterator_category = std::forward_iterator_tag;
    286 
    287   explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
    288     : SmallPtrSetIteratorImpl(BP, E) {}
    289 
    290   // Most methods provided by baseclass.
    291 
    292   const PtrTy operator*() const {
    293 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
    294     if (ReverseIterate<bool>::value) {
    295       assert(Bucket > End);
    296       return PtrTraits::getFromVoidPointer(const_cast<void *>(Bucket[-1]));
    297     }
    298 #endif
    299     assert(Bucket < End);
    300     return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket));
    301   }
    302 
    303   inline SmallPtrSetIterator& operator++() {          // Preincrement
    304 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
    305     if (ReverseIterate<bool>::value) {
    306       --Bucket;
    307       RetreatIfNotValid();
    308       return *this;
    309     }
    310 #endif
    311     ++Bucket;
    312     AdvanceIfNotValid();
    313     return *this;
    314   }
    315 
    316   SmallPtrSetIterator operator++(int) {        // Postincrement
    317     SmallPtrSetIterator tmp = *this;
    318     ++*this;
    319     return tmp;
    320   }
    321 };
    322 
    323 /// RoundUpToPowerOfTwo - This is a helper template that rounds N up to the next
    324 /// power of two (which means N itself if N is already a power of two).
    325 template<unsigned N>
    326 struct RoundUpToPowerOfTwo;
    327 
    328 /// RoundUpToPowerOfTwoH - If N is not a power of two, increase it.  This is a
    329 /// helper template used to implement RoundUpToPowerOfTwo.
    330 template<unsigned N, bool isPowerTwo>
    331 struct RoundUpToPowerOfTwoH {
    332   enum { Val = N };
    333 };
    334 template<unsigned N>
    335 struct RoundUpToPowerOfTwoH<N, false> {
    336   enum {
    337     // We could just use NextVal = N+1, but this converges faster.  N|(N-1) sets
    338     // the right-most zero bits to one all at once, e.g. 0b0011000 -> 0b0011111.
    339     Val = RoundUpToPowerOfTwo<(N|(N-1)) + 1>::Val
    340   };
    341 };
    342 
    343 template<unsigned N>
    344 struct RoundUpToPowerOfTwo {
    345   enum { Val = RoundUpToPowerOfTwoH<N, (N&(N-1)) == 0>::Val };
    346 };
    347 
    348 /// \brief A templated base class for \c SmallPtrSet which provides the
    349 /// typesafe interface that is common across all small sizes.
    350 ///
    351 /// This is particularly useful for passing around between interface boundaries
    352 /// to avoid encoding a particular small size in the interface boundary.
    353 template <typename PtrType>
    354 class SmallPtrSetImpl : public SmallPtrSetImplBase {
    355   using ConstPtrType = typename add_const_past_pointer<PtrType>::type;
    356   using PtrTraits = PointerLikeTypeTraits<PtrType>;
    357   using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
    358 
    359 protected:
    360   // Constructors that forward to the base.
    361   SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that)
    362       : SmallPtrSetImplBase(SmallStorage, that) {}
    363   SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize,
    364                   SmallPtrSetImpl &&that)
    365       : SmallPtrSetImplBase(SmallStorage, SmallSize, std::move(that)) {}
    366   explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize)
    367       : SmallPtrSetImplBase(SmallStorage, SmallSize) {}
    368 
    369 public:
    370   using iterator = SmallPtrSetIterator<PtrType>;
    371   using const_iterator = SmallPtrSetIterator<PtrType>;
    372   using key_type = ConstPtrType;
    373   using value_type = PtrType;
    374 
    375   SmallPtrSetImpl(const SmallPtrSetImpl &) = delete;
    376 
    377   /// Inserts Ptr if and only if there is no element in the container equal to
    378   /// Ptr. The bool component of the returned pair is true if and only if the
    379   /// insertion takes place, and the iterator component of the pair points to
    380   /// the element equal to Ptr.
    381   std::pair<iterator, bool> insert(PtrType Ptr) {
    382     auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr));
    383     return std::make_pair(makeIterator(p.first), p.second);
    384   }
    385 
    386   /// erase - If the set contains the specified pointer, remove it and return
    387   /// true, otherwise return false.
    388   bool erase(PtrType Ptr) {
    389     return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
    390   }
    391   /// count - Return 1 if the specified pointer is in the set, 0 otherwise.
    392   size_type count(ConstPtrType Ptr) const { return find(Ptr) != end() ? 1 : 0; }
    393   iterator find(ConstPtrType Ptr) const {
    394     return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)));
    395   }
    396 
    397   template <typename IterT>
    398   void insert(IterT I, IterT E) {
    399     for (; I != E; ++I)
    400       insert(*I);
    401   }
    402 
    403   void insert(std::initializer_list<PtrType> IL) {
    404     insert(IL.begin(), IL.end());
    405   }
    406 
    407   iterator begin() const {
    408 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
    409     if (ReverseIterate<bool>::value)
    410       return makeIterator(EndPointer() - 1);
    411 #endif
    412     return makeIterator(CurArray);
    413   }
    414   iterator end() const { return makeIterator(EndPointer()); }
    415 
    416 private:
    417   /// Create an iterator that dereferences to same place as the given pointer.
    418   iterator makeIterator(const void *const *P) const {
    419 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
    420     if (ReverseIterate<bool>::value)
    421       return iterator(P == EndPointer() ? CurArray : P + 1, CurArray);
    422 #endif
    423     return iterator(P, EndPointer());
    424   }
    425 };
    426 
    427 /// SmallPtrSet - This class implements a set which is optimized for holding
    428 /// SmallSize or less elements.  This internally rounds up SmallSize to the next
    429 /// power of two if it is not already a power of two.  See the comments above
    430 /// SmallPtrSetImplBase for details of the algorithm.
    431 template<class PtrType, unsigned SmallSize>
    432 class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
    433   // In small mode SmallPtrSet uses linear search for the elements, so it is
    434   // not a good idea to choose this value too high. You may consider using a
    435   // DenseSet<> instead if you expect many elements in the set.
    436   static_assert(SmallSize <= 32, "SmallSize should be small");
    437 
    438   using BaseT = SmallPtrSetImpl<PtrType>;
    439 
    440   // Make sure that SmallSize is a power of two, round up if not.
    441   enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
    442   /// SmallStorage - Fixed size storage used in 'small mode'.
    443   const void *SmallStorage[SmallSizePowTwo];
    444 
    445 public:
    446   SmallPtrSet() : BaseT(SmallStorage, SmallSizePowTwo) {}
    447   SmallPtrSet(const SmallPtrSet &that) : BaseT(SmallStorage, that) {}
    448   SmallPtrSet(SmallPtrSet &&that)
    449       : BaseT(SmallStorage, SmallSizePowTwo, std::move(that)) {}
    450 
    451   template<typename It>
    452   SmallPtrSet(It I, It E) : BaseT(SmallStorage, SmallSizePowTwo) {
    453     this->insert(I, E);
    454   }
    455 
    456   SmallPtrSet(std::initializer_list<PtrType> IL)
    457       : BaseT(SmallStorage, SmallSizePowTwo) {
    458     this->insert(IL.begin(), IL.end());
    459   }
    460 
    461   SmallPtrSet<PtrType, SmallSize> &
    462   operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
    463     if (&RHS != this)
    464       this->CopyFrom(RHS);
    465     return *this;
    466   }
    467 
    468   SmallPtrSet<PtrType, SmallSize> &
    469   operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
    470     if (&RHS != this)
    471       this->MoveFrom(SmallSizePowTwo, std::move(RHS));
    472     return *this;
    473   }
    474 
    475   SmallPtrSet<PtrType, SmallSize> &
    476   operator=(std::initializer_list<PtrType> IL) {
    477     this->clear();
    478     this->insert(IL.begin(), IL.end());
    479     return *this;
    480   }
    481 
    482   /// swap - Swaps the elements of two sets.
    483   void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
    484     SmallPtrSetImplBase::swap(RHS);
    485   }
    486 };
    487 
    488 } // end namespace llvm
    489 
    490 namespace std {
    491 
    492   /// Implement std::swap in terms of SmallPtrSet swap.
    493   template<class T, unsigned N>
    494   inline void swap(llvm::SmallPtrSet<T, N> &LHS, llvm::SmallPtrSet<T, N> &RHS) {
    495     LHS.swap(RHS);
    496   }
    497 
    498 } // end namespace std
    499 
    500 #endif // LLVM_ADT_SMALLPTRSET_H
    501