//
//===----------------------------------------------------------------------===//
//
-// This file defines the SmallPtrSet class.
+// This file defines the SmallPtrSet class. See the doxygen comment for
+// SmallPtrSetImpl for more details on the algorithm used.
//
//===----------------------------------------------------------------------===//
#include <cassert>
#include <cstring>
+#include "llvm/Support/DataTypes.h"
namespace llvm {
+/// SmallPtrSetImpl - This is the common code shared among all the
+/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
+/// for small and one for large sets.
+///
+/// Small sets use an array of pointers allocated in the SmallPtrSet object,
+/// which is treated as a simple array of pointers. When a pointer is added to
+/// the set, the array is scanned to see if the element already exists, if not
+/// the element is 'pushed back' onto the array. If we run out of space in the
+/// array, we grow into the 'large set' case. SmallSet should be used when the
+/// sets are often small. In this case, no memory allocation is used, and only
+/// light-weight and cache-efficient scanning is used.
+///
+/// Large sets use a classic exponentially-probed hash table. Empty buckets are
+/// represented with an illegal pointer value (-1) to allow null pointers to be
+/// inserted. Tombstones are represented with another illegal pointer value
+/// (-2), to allow deletion. The hash table is resized when the table is 3/4 or
+/// more. When this happens, the table is doubled in size.
+///
class SmallPtrSetImpl {
protected:
/// CurArray - This is the current set of buckets. If it points to
// If small, this is # elts allocated consequtively
unsigned NumElements;
+ unsigned NumTombstones;
void *SmallArray[1]; // Must be last ivar.
public:
SmallPtrSetImpl(unsigned SmallSize) {
delete[] CurArray;
}
- bool isSmall() const { return CurArray == &SmallArray[0]; }
-
+ bool empty() const { return size() == 0; }
+ unsigned size() const { return NumElements; }
+
static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); }
static void *getEmptyMarker() {
// Note that -1 is chosen to make clear() efficiently implementable with
// Fill the array with empty markers.
memset(CurArray, -1, CurArraySize*sizeof(void*));
NumElements = 0;
+ NumTombstones = 0;
}
/// insert - This returns true if the pointer was new to the set, false if it
/// was already in the set.
bool insert(void *Ptr);
+ /// erase - If the set contains the specified pointer, remove it and return
+ /// true, otherwise return false.
+ bool erase(void *Ptr);
+
bool count(void *Ptr) const {
if (isSmall()) {
// Linear search for the item.
}
private:
+ bool isSmall() const { return CurArray == &SmallArray[0]; }
+
unsigned Hash(void *Ptr) const {
return ((uintptr_t)Ptr >> 4) & (CurArraySize-1);
}
}
};
+/// NextPowerOfTwo - This is a helper template that rounds N up to the next
+/// power of two.
+template<unsigned N>
+struct NextPowerOfTwo;
+
+/// NextPowerOfTwoH - If N is not a power of two, increase it. This is a helper
+/// template used to implement NextPowerOfTwo.
+template<unsigned N, bool isPowerTwo>
+struct NextPowerOfTwoH {
+ enum { Val = N };
+};
+template<unsigned N>
+struct NextPowerOfTwoH<N, false> {
+ enum {
+ // We could just use NextVal = N+1, but this converges faster. N|(N-1) sets
+ // the right-most zero bits to one all at once, e.g. 0b0011000 -> 0b0011111.
+ Val = NextPowerOfTwo<(N|(N-1)) + 1>::Val
+ };
+};
+
+template<unsigned N>
+struct NextPowerOfTwo {
+ enum { Val = NextPowerOfTwoH<N, (N&(N-1)) == 0>::Val };
+};
+
-/// SmallPtrSet - This class implements
+/// SmallPtrSet - This class implements a set which is optimizer for holding
+/// SmallSize or less elements. This internally rounds up SmallSize to the next
+/// power of two if it is not already a power of two. See the comments above
+/// SmallPtrSetImpl for details of the algorithm.
template<class PtrType, unsigned SmallSize>
class SmallPtrSet : public SmallPtrSetImpl {
- void *SmallArray[SmallSize];
+ // Make sure that SmallSize is a power of two, round up if not.
+ enum { SmallSizePowTwo = NextPowerOfTwo<SmallSize>::Val };
+ void *SmallArray[SmallSizePowTwo];
public:
- SmallPtrSet() : SmallPtrSetImpl(SmallSize) {}
+ SmallPtrSet() : SmallPtrSetImpl(NextPowerOfTwo<SmallSizePowTwo>::Val) {}
typedef SmallPtrSetIterator<PtrType> iterator;
typedef SmallPtrSetIterator<PtrType> const_iterator;