aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/ADT/SmallPtrSet.h165
-rw-r--r--lib/Support/SmallPtrSet.cpp113
2 files changed, 278 insertions, 0 deletions
diff --git a/include/llvm/ADT/SmallPtrSet.h b/include/llvm/ADT/SmallPtrSet.h
new file mode 100644
index 0000000000..a1ce7ba0dc
--- /dev/null
+++ b/include/llvm/ADT/SmallPtrSet.h
@@ -0,0 +1,165 @@
+//===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the SmallPtrSet class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_ADT_SMALLPTRSET_H
+#define LLVM_ADT_SMALLPTRSET_H
+
+#include <cassert>
+#include <cstring>
+
+namespace llvm {
+
+class SmallPtrSetImpl {
+protected:
+ /// CurArray - This is the current set of buckets. If it points to
+ /// SmallArray, then the set is in 'small mode'.
+ void **CurArray;
+ /// CurArraySize - The allocated size of CurArray, always a power of two.
+ /// Note that CurArray points to an array that has CurArraySize+1 elements in
+ /// it, so that the end iterator actually points to valid memory.
+ unsigned CurArraySize;
+
+ // If small, this is # elts allocated consequtively
+ unsigned NumElements;
+ void *SmallArray[1]; // Must be last ivar.
+public:
+ SmallPtrSetImpl(unsigned SmallSize) {
+ assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
+ "Initial size must be a power of two!");
+ CurArray = &SmallArray[0];
+ CurArraySize = SmallSize;
+ // The end pointer, always valid, is set to a valid element to help the
+ // iterator.
+ CurArray[SmallSize] = 0;
+ clear();
+ }
+ ~SmallPtrSetImpl() {
+ if (!isSmall())
+ delete[] CurArray;
+ }
+
+ bool isSmall() const { return CurArray == &SmallArray[0]; }
+
+ static void *getTombstoneMarker() { return reinterpret_cast<void*>(-2); }
+ static void *getEmptyMarker() {
+ // Note that -1 is chosen to make clear() efficiently implementable with
+ // memset and because it's not a valid pointer value.
+ return reinterpret_cast<void*>(-1);
+ }
+
+ void clear() {
+ // Fill the array with empty markers.
+ memset(CurArray, -1, CurArraySize*sizeof(void*));
+ NumElements = 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);
+
+ bool count(void *Ptr) const {
+ if (isSmall()) {
+ // Linear search for the item.
+ for (void *const *APtr = SmallArray, *const *E = SmallArray+NumElements;
+ APtr != E; ++APtr)
+ if (*APtr == Ptr)
+ return true;
+ return false;
+ }
+
+ // Big set case.
+ return *FindBucketFor(Ptr) == Ptr;
+ }
+
+private:
+ unsigned Hash(void *Ptr) const {
+ return ((uintptr_t)Ptr >> 4) & (CurArraySize-1);
+ }
+ void * const *FindBucketFor(void *Ptr) const;
+
+ /// Grow - Allocate a larger backing store for the buckets and move it over.
+ void Grow();
+};
+
+/// SmallPtrSetIteratorImpl - This is the common base class shared between all
+/// instances of SmallPtrSetIterator.
+class SmallPtrSetIteratorImpl {
+protected:
+ void *const *Bucket;
+public:
+ SmallPtrSetIteratorImpl(void *const *BP) : Bucket(BP) {
+ AdvanceIfNotValid();
+ }
+
+ bool operator==(const SmallPtrSetIteratorImpl &RHS) const {
+ return Bucket == RHS.Bucket;
+ }
+ bool operator!=(const SmallPtrSetIteratorImpl &RHS) const {
+ return Bucket != RHS.Bucket;
+ }
+
+protected:
+ /// AdvanceIfNotValid - If the current bucket isn't valid, advance to a bucket
+ /// that is. This is guaranteed to stop because the end() bucket is marked
+ /// valid.
+ void AdvanceIfNotValid() {
+ while (*Bucket == SmallPtrSetImpl::getEmptyMarker() ||
+ *Bucket == SmallPtrSetImpl::getTombstoneMarker())
+ ++Bucket;
+ }
+};
+
+/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
+template<typename PtrTy>
+class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
+public:
+ SmallPtrSetIterator(void *const *BP) : SmallPtrSetIteratorImpl(BP) {}
+
+ // Most methods provided by baseclass.
+
+ PtrTy operator*() const {
+ return static_cast<PtrTy>(*Bucket);
+ }
+
+ inline SmallPtrSetIterator& operator++() { // Preincrement
+ ++Bucket;
+ AdvanceIfNotValid();
+ return *this;
+ }
+
+ SmallPtrSetIterator operator++(int) { // Postincrement
+ SmallPtrSetIterator tmp = *this; ++*this; return tmp;
+ }
+};
+
+
+/// SmallPtrSet - This class implements
+template<class PtrType, unsigned SmallSize>
+class SmallPtrSet : public SmallPtrSetImpl {
+ void *SmallArray[SmallSize];
+public:
+ SmallPtrSet() : SmallPtrSetImpl(SmallSize) {}
+
+ typedef SmallPtrSetIterator<PtrType> iterator;
+ typedef SmallPtrSetIterator<PtrType> const_iterator;
+ inline iterator begin() const {
+ return iterator(CurArray);
+ }
+ inline iterator end() const {
+ return iterator(CurArray+CurArraySize);
+ }
+};
+
+}
+
+#endif
diff --git a/lib/Support/SmallPtrSet.cpp b/lib/Support/SmallPtrSet.cpp
new file mode 100644
index 0000000000..0e6d334590
--- /dev/null
+++ b/lib/Support/SmallPtrSet.cpp
@@ -0,0 +1,113 @@
+//===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file was developed by Chris Lattner and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the SmallPtrSet class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallPtrSet.h"
+using namespace llvm;
+
+bool SmallPtrSetImpl::insert(void *Ptr) {
+ if (isSmall()) {
+ // Check to see if it is already in the set.
+ for (void **APtr = SmallArray, **E = SmallArray+NumElements;
+ APtr != E; ++APtr)
+ if (*APtr == Ptr)
+ return false;
+
+ // Nope, there isn't. If we stay small, just 'pushback' now.
+ if (NumElements < CurArraySize-1) {
+ SmallArray[NumElements++] = Ptr;
+ return true;
+ }
+ // Otherwise, hit the big set case, which will call grow.
+ }
+
+ // If more than 3/4 of the array is full, grow.
+ if (NumElements*4 >= CurArraySize*3)
+ Grow();
+
+ // Okay, we know we have space. Find a hash bucket.
+ void **Bucket = const_cast<void**>(FindBucketFor(Ptr));
+ if (*Bucket == Ptr) return false; // Already inserted, good.
+
+ // Otherwise, insert it!
+ *Bucket = Ptr;
+ ++NumElements; // Track density.
+ return true;
+}
+
+void * const *SmallPtrSetImpl::FindBucketFor(void *Ptr) const {
+ unsigned Bucket = Hash(Ptr);
+ unsigned ArraySize = CurArraySize;
+ unsigned ProbeAmt = 1;
+ void *const *Array = CurArray;
+ void *const *Tombstone = 0;
+ while (1) {
+ // Found Ptr's bucket?
+ if (Array[Bucket] == Ptr)
+ return Array+Bucket;
+
+ // If we found an empty bucket, the pointer doesn't exist in the set.
+ // Return a tombstone if we've seen one so far, or the empty bucket if
+ // not.
+ if (Array[Bucket] == getEmptyMarker())
+ return Tombstone ? Tombstone : Array+Bucket;
+
+ // If this is a tombstone, remember it. If Ptr ends up not in the set, we
+ // prefer to return it than something that would require more probing.
+ if (Array[Bucket] == getTombstoneMarker() && !Tombstone)
+ Tombstone = Array+Bucket; // Remember the first tombstone found.
+
+ // It's a hash collision or a tombstone. Reprobe.
+ Bucket = (Bucket + ProbeAmt++) & (ArraySize-1);
+ }
+}
+
+/// Grow - Allocate a larger backing store for the buckets and move it over.
+///
+void SmallPtrSetImpl::Grow() {
+ // Allocate at twice as many buckets, but at least 128.
+ unsigned OldSize = CurArraySize;
+ unsigned NewSize = OldSize < 64 ? 128 : OldSize*2;
+
+ void **OldBuckets = CurArray;
+ bool WasSmall = isSmall();
+
+ // Install the new array. Clear all the buckets to empty.
+ CurArray = new void*[NewSize+1];
+ CurArraySize = NewSize;
+ memset(CurArray, -1, NewSize*sizeof(void*));
+
+ // The end pointer, always valid, is set to a valid element to help the
+ // iterator.
+ CurArray[NewSize] = 0;
+
+ // Copy over all the elements.
+ if (WasSmall) {
+ // Small sets store their elements in order.
+ for (void **BucketPtr = OldBuckets, **E = OldBuckets+NumElements;
+ BucketPtr != E; ++BucketPtr) {
+ void *Elt = *BucketPtr;
+ *const_cast<void**>(FindBucketFor(Elt)) = Elt;
+ }
+ } else {
+ // Copy over all valid entries.
+ for (void **BucketPtr = OldBuckets, **E = OldBuckets+OldSize;
+ BucketPtr != E; ++BucketPtr) {
+ // Copy over the element if it is valid.
+ void *Elt = *BucketPtr;
+ if (Elt != getTombstoneMarker() && Elt != getEmptyMarker())
+ *const_cast<void**>(FindBucketFor(Elt)) = Elt;
+ }
+
+ delete [] OldBuckets;
+ }
+}