llvm.org GIT mirror llvm / c95dc98
Add a new SmallSet ADT specialized for pointers. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@33577 91177308-0d34-0410-b5e6-96231b3b80d8 Chris Lattner 13 years ago
2 changed file(s) with 278 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file was developed by Chris Lattner and is distributed under
5 // the University of Illinois Open Source License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the SmallPtrSet class.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_ADT_SMALLPTRSET_H
14 #define LLVM_ADT_SMALLPTRSET_H
15
16 #include
17 #include
18
19 namespace llvm {
20
21 class SmallPtrSetImpl {
22 protected:
23 /// CurArray - This is the current set of buckets. If it points to
24 /// SmallArray, then the set is in 'small mode'.
25 void **CurArray;
26 /// CurArraySize - The allocated size of CurArray, always a power of two.
27 /// Note that CurArray points to an array that has CurArraySize+1 elements in
28 /// it, so that the end iterator actually points to valid memory.
29 unsigned CurArraySize;
30
31 // If small, this is # elts allocated consequtively
32 unsigned NumElements;
33 void *SmallArray[1]; // Must be last ivar.
34 public:
35 SmallPtrSetImpl(unsigned SmallSize) {
36 assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
37 "Initial size must be a power of two!");
38 CurArray = &SmallArray[0];
39 CurArraySize = SmallSize;
40 // The end pointer, always valid, is set to a valid element to help the
41 // iterator.
42 CurArray[SmallSize] = 0;
43 clear();
44 }
45 ~SmallPtrSetImpl() {
46 if (!isSmall())
47 delete[] CurArray;
48 }
49
50 bool isSmall() const { return CurArray == &SmallArray[0]; }
51
52 static void *getTombstoneMarker() { return reinterpret_cast(-2); }
53 static void *getEmptyMarker() {
54 // Note that -1 is chosen to make clear() efficiently implementable with
55 // memset and because it's not a valid pointer value.
56 return reinterpret_cast(-1);
57 }
58
59 void clear() {
60 // Fill the array with empty markers.
61 memset(CurArray, -1, CurArraySize*sizeof(void*));
62 NumElements = 0;
63 }
64
65 /// insert - This returns true if the pointer was new to the set, false if it
66 /// was already in the set.
67 bool insert(void *Ptr);
68
69 bool count(void *Ptr) const {
70 if (isSmall()) {
71 // Linear search for the item.
72 for (void *const *APtr = SmallArray, *const *E = SmallArray+NumElements;
73 APtr != E; ++APtr)
74 if (*APtr == Ptr)
75 return true;
76 return false;
77 }
78
79 // Big set case.
80 return *FindBucketFor(Ptr) == Ptr;
81 }
82
83 private:
84 unsigned Hash(void *Ptr) const {
85 return ((uintptr_t)Ptr >> 4) & (CurArraySize-1);
86 }
87 void * const *FindBucketFor(void *Ptr) const;
88
89 /// Grow - Allocate a larger backing store for the buckets and move it over.
90 void Grow();
91 };
92
93 /// SmallPtrSetIteratorImpl - This is the common base class shared between all
94 /// instances of SmallPtrSetIterator.
95 class SmallPtrSetIteratorImpl {
96 protected:
97 void *const *Bucket;
98 public:
99 SmallPtrSetIteratorImpl(void *const *BP) : Bucket(BP) {
100 AdvanceIfNotValid();
101 }
102
103 bool operator==(const SmallPtrSetIteratorImpl &RHS) const {
104 return Bucket == RHS.Bucket;
105 }
106 bool operator!=(const SmallPtrSetIteratorImpl &RHS) const {
107 return Bucket != RHS.Bucket;
108 }
109
110 protected:
111 /// AdvanceIfNotValid - If the current bucket isn't valid, advance to a bucket
112 /// that is. This is guaranteed to stop because the end() bucket is marked
113 /// valid.
114 void AdvanceIfNotValid() {
115 while (*Bucket == SmallPtrSetImpl::getEmptyMarker() ||
116 *Bucket == SmallPtrSetImpl::getTombstoneMarker())
117 ++Bucket;
118 }
119 };
120
121 /// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
122 template
123 class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
124 public:
125 SmallPtrSetIterator(void *const *BP) : SmallPtrSetIteratorImpl(BP) {}
126
127 // Most methods provided by baseclass.
128
129 PtrTy operator*() const {
130 return static_cast(*Bucket);
131 }
132
133 inline SmallPtrSetIterator& operator++() { // Preincrement
134 ++Bucket;
135 AdvanceIfNotValid();
136 return *this;
137 }
138
139 SmallPtrSetIterator operator++(int) { // Postincrement
140 SmallPtrSetIterator tmp = *this; ++*this; return tmp;
141 }
142 };
143
144
145 /// SmallPtrSet - This class implements
146 template
147 class SmallPtrSet : public SmallPtrSetImpl {
148 void *SmallArray[SmallSize];
149 public:
150 SmallPtrSet() : SmallPtrSetImpl(SmallSize) {}
151
152 typedef SmallPtrSetIterator iterator;
153 typedef SmallPtrSetIterator const_iterator;
154 inline iterator begin() const {
155 return iterator(CurArray);
156 }
157 inline iterator end() const {
158 return iterator(CurArray+CurArraySize);
159 }
160 };
161
162 }
163
164 #endif
0 //===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file was developed by Chris Lattner and is distributed under
5 // the University of Illinois Open Source License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the SmallPtrSet class.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/ADT/SmallPtrSet.h"
14 using namespace llvm;
15
16 bool SmallPtrSetImpl::insert(void *Ptr) {
17 if (isSmall()) {
18 // Check to see if it is already in the set.
19 for (void **APtr = SmallArray, **E = SmallArray+NumElements;
20 APtr != E; ++APtr)
21 if (*APtr == Ptr)
22 return false;
23
24 // Nope, there isn't. If we stay small, just 'pushback' now.
25 if (NumElements < CurArraySize-1) {
26 SmallArray[NumElements++] = Ptr;
27 return true;
28 }
29 // Otherwise, hit the big set case, which will call grow.
30 }
31
32 // If more than 3/4 of the array is full, grow.
33 if (NumElements*4 >= CurArraySize*3)
34 Grow();
35
36 // Okay, we know we have space. Find a hash bucket.
37 void **Bucket = const_cast(FindBucketFor(Ptr));
38 if (*Bucket == Ptr) return false; // Already inserted, good.
39
40 // Otherwise, insert it!
41 *Bucket = Ptr;
42 ++NumElements; // Track density.
43 return true;
44 }
45
46 void * const *SmallPtrSetImpl::FindBucketFor(void *Ptr) const {
47 unsigned Bucket = Hash(Ptr);
48 unsigned ArraySize = CurArraySize;
49 unsigned ProbeAmt = 1;
50 void *const *Array = CurArray;
51 void *const *Tombstone = 0;
52 while (1) {
53 // Found Ptr's bucket?
54 if (Array[Bucket] == Ptr)
55 return Array+Bucket;
56
57 // If we found an empty bucket, the pointer doesn't exist in the set.
58 // Return a tombstone if we've seen one so far, or the empty bucket if
59 // not.
60 if (Array[Bucket] == getEmptyMarker())
61 return Tombstone ? Tombstone : Array+Bucket;
62
63 // If this is a tombstone, remember it. If Ptr ends up not in the set, we
64 // prefer to return it than something that would require more probing.
65 if (Array[Bucket] == getTombstoneMarker() && !Tombstone)
66 Tombstone = Array+Bucket; // Remember the first tombstone found.
67
68 // It's a hash collision or a tombstone. Reprobe.
69 Bucket = (Bucket + ProbeAmt++) & (ArraySize-1);
70 }
71 }
72
73 /// Grow - Allocate a larger backing store for the buckets and move it over.
74 ///
75 void SmallPtrSetImpl::Grow() {
76 // Allocate at twice as many buckets, but at least 128.
77 unsigned OldSize = CurArraySize;
78 unsigned NewSize = OldSize < 64 ? 128 : OldSize*2;
79
80 void **OldBuckets = CurArray;
81 bool WasSmall = isSmall();
82
83 // Install the new array. Clear all the buckets to empty.
84 CurArray = new void*[NewSize+1];
85 CurArraySize = NewSize;
86 memset(CurArray, -1, NewSize*sizeof(void*));
87
88 // The end pointer, always valid, is set to a valid element to help the
89 // iterator.
90 CurArray[NewSize] = 0;
91
92 // Copy over all the elements.
93 if (WasSmall) {
94 // Small sets store their elements in order.
95 for (void **BucketPtr = OldBuckets, **E = OldBuckets+NumElements;
96 BucketPtr != E; ++BucketPtr) {
97 void *Elt = *BucketPtr;
98 *const_cast(FindBucketFor(Elt)) = Elt;
99 }
100 } else {
101 // Copy over all valid entries.
102 for (void **BucketPtr = OldBuckets, **E = OldBuckets+OldSize;
103 BucketPtr != E; ++BucketPtr) {
104 // Copy over the element if it is valid.
105 void *Elt = *BucketPtr;
106 if (Elt != getTombstoneMarker() && Elt != getEmptyMarker())
107 *const_cast(FindBucketFor(Elt)) = Elt;
108 }
109
110 delete [] OldBuckets;
111 }
112 }