1 //===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the SmallPtrSet class. See SmallPtrSet.h for an
11 // overview of the algorithm.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/ADT/SmallPtrSet.h"
16 #include "llvm/Support/MathExtras.h"
21 void SmallPtrSetImpl::shrink_and_clear() {
22 assert(!isSmall() && "Can't shrink a small set!");
25 // Reduce the number of buckets.
26 CurArraySize
= NumElements
> 16 ? 1 << (Log2_32_Ceil(NumElements
) + 1) : 32;
27 NumElements
= NumTombstones
= 0;
29 // Install the new array. Clear all the buckets to empty.
30 CurArray
= (const void**)malloc(sizeof(void*) * (CurArraySize
+1));
31 assert(CurArray
&& "Failed to allocate memory?");
32 memset(CurArray
, -1, CurArraySize
*sizeof(void*));
34 // The end pointer, always valid, is set to a valid element to help the
36 CurArray
[CurArraySize
] = 0;
39 bool SmallPtrSetImpl::insert_imp(const void * Ptr
) {
41 // Check to see if it is already in the set.
42 for (const void **APtr
= SmallArray
, **E
= SmallArray
+NumElements
;
47 // Nope, there isn't. If we stay small, just 'pushback' now.
48 if (NumElements
< CurArraySize
-1) {
49 SmallArray
[NumElements
++] = Ptr
;
52 // Otherwise, hit the big set case, which will call grow.
55 // If more than 3/4 of the array is full, grow.
56 if (NumElements
*4 >= CurArraySize
*3 ||
57 CurArraySize
-(NumElements
+NumTombstones
) < CurArraySize
/8)
60 // Okay, we know we have space. Find a hash bucket.
61 const void **Bucket
= const_cast<const void**>(FindBucketFor(Ptr
));
62 if (*Bucket
== Ptr
) return false; // Already inserted, good.
64 // Otherwise, insert it!
65 if (*Bucket
== getTombstoneMarker())
68 ++NumElements
; // Track density.
72 bool SmallPtrSetImpl::erase_imp(const void * Ptr
) {
74 // Check to see if it is in the set.
75 for (const void **APtr
= SmallArray
, **E
= SmallArray
+NumElements
;
78 // If it is in the set, replace this element.
80 E
[-1] = getEmptyMarker();
88 // Okay, we know we have space. Find a hash bucket.
89 void **Bucket
= const_cast<void**>(FindBucketFor(Ptr
));
90 if (*Bucket
!= Ptr
) return false; // Not in the set?
92 // Set this as a tombstone.
93 *Bucket
= getTombstoneMarker();
99 const void * const *SmallPtrSetImpl::FindBucketFor(const void *Ptr
) const {
100 unsigned Bucket
= Hash(Ptr
);
101 unsigned ArraySize
= CurArraySize
;
102 unsigned ProbeAmt
= 1;
103 const void *const *Array
= CurArray
;
104 const void *const *Tombstone
= 0;
106 // Found Ptr's bucket?
107 if (Array
[Bucket
] == Ptr
)
110 // If we found an empty bucket, the pointer doesn't exist in the set.
111 // Return a tombstone if we've seen one so far, or the empty bucket if
113 if (Array
[Bucket
] == getEmptyMarker())
114 return Tombstone
? Tombstone
: Array
+Bucket
;
116 // If this is a tombstone, remember it. If Ptr ends up not in the set, we
117 // prefer to return it than something that would require more probing.
118 if (Array
[Bucket
] == getTombstoneMarker() && !Tombstone
)
119 Tombstone
= Array
+Bucket
; // Remember the first tombstone found.
121 // It's a hash collision or a tombstone. Reprobe.
122 Bucket
= (Bucket
+ ProbeAmt
++) & (ArraySize
-1);
126 /// Grow - Allocate a larger backing store for the buckets and move it over.
128 void SmallPtrSetImpl::Grow() {
129 // Allocate at twice as many buckets, but at least 128.
130 unsigned OldSize
= CurArraySize
;
131 unsigned NewSize
= OldSize
< 64 ? 128 : OldSize
*2;
133 const void **OldBuckets
= CurArray
;
134 bool WasSmall
= isSmall();
136 // Install the new array. Clear all the buckets to empty.
137 CurArray
= (const void**)malloc(sizeof(void*) * (NewSize
+1));
138 assert(CurArray
&& "Failed to allocate memory?");
139 CurArraySize
= NewSize
;
140 memset(CurArray
, -1, NewSize
*sizeof(void*));
142 // The end pointer, always valid, is set to a valid element to help the
144 CurArray
[NewSize
] = 0;
146 // Copy over all the elements.
148 // Small sets store their elements in order.
149 for (const void **BucketPtr
= OldBuckets
, **E
= OldBuckets
+NumElements
;
150 BucketPtr
!= E
; ++BucketPtr
) {
151 const void *Elt
= *BucketPtr
;
152 *const_cast<void**>(FindBucketFor(Elt
)) = const_cast<void*>(Elt
);
155 // Copy over all valid entries.
156 for (const void **BucketPtr
= OldBuckets
, **E
= OldBuckets
+OldSize
;
157 BucketPtr
!= E
; ++BucketPtr
) {
158 // Copy over the element if it is valid.
159 const void *Elt
= *BucketPtr
;
160 if (Elt
!= getTombstoneMarker() && Elt
!= getEmptyMarker())
161 *const_cast<void**>(FindBucketFor(Elt
)) = const_cast<void*>(Elt
);
169 SmallPtrSetImpl::SmallPtrSetImpl(const SmallPtrSetImpl
& that
) {
170 // If we're becoming small, prepare to insert into our stack space
171 if (that
.isSmall()) {
172 CurArray
= &SmallArray
[0];
173 // Otherwise, allocate new heap space (unless we were the same size)
175 CurArray
= (const void**)malloc(sizeof(void*) * (that
.CurArraySize
+1));
176 assert(CurArray
&& "Failed to allocate memory?");
179 // Copy over the new array size
180 CurArraySize
= that
.CurArraySize
;
182 // Copy over the contents from the other set
183 memcpy(CurArray
, that
.CurArray
, sizeof(void*)*(CurArraySize
+1));
185 NumElements
= that
.NumElements
;
186 NumTombstones
= that
.NumTombstones
;
189 /// CopyFrom - implement operator= from a smallptrset that has the same pointer
190 /// type, but may have a different small size.
191 void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl
&RHS
) {
192 if (isSmall() && RHS
.isSmall())
193 assert(CurArraySize
== RHS
.CurArraySize
&&
194 "Cannot assign sets with different small sizes");
196 // If we're becoming small, prepare to insert into our stack space
200 CurArray
= &SmallArray
[0];
201 // Otherwise, allocate new heap space (unless we were the same size)
202 } else if (CurArraySize
!= RHS
.CurArraySize
) {
204 CurArray
= (const void**)malloc(sizeof(void*) * (RHS
.CurArraySize
+1));
206 CurArray
= (const void**)realloc(CurArray
, sizeof(void*)*(RHS
.CurArraySize
+1));
207 assert(CurArray
&& "Failed to allocate memory?");
210 // Copy over the new array size
211 CurArraySize
= RHS
.CurArraySize
;
213 // Copy over the contents from the other set
214 memcpy(CurArray
, RHS
.CurArray
, sizeof(void*)*(CurArraySize
+1));
216 NumElements
= RHS
.NumElements
;
217 NumTombstones
= RHS
.NumTombstones
;
220 SmallPtrSetImpl::~SmallPtrSetImpl() {