LLVM API Documentation

SmallPtrSet.cpp

Go to the documentation of this file.
00001 //===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file implements the SmallPtrSet class.  See SmallPtrSet.h for an
00011 // overview of the algorithm.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #include "llvm/ADT/SmallPtrSet.h"
00016 #include "llvm/Support/MathExtras.h"
00017 #include <cstdlib>
00018 
00019 using namespace llvm;
00020 
00021 void SmallPtrSetImpl::shrink_and_clear() {
00022   assert(!isSmall() && "Can't shrink a small set!");
00023   free(CurArray);
00024 
00025   // Reduce the number of buckets.
00026   CurArraySize = NumElements > 16 ? 1 << (Log2_32_Ceil(NumElements) + 1) : 32;
00027   NumElements = NumTombstones = 0;
00028 
00029   // Install the new array.  Clear all the buckets to empty.
00030   CurArray = (const void**)malloc(sizeof(void*) * (CurArraySize+1));
00031   assert(CurArray && "Failed to allocate memory?");
00032   memset(CurArray, -1, CurArraySize*sizeof(void*));
00033   
00034   // The end pointer, always valid, is set to a valid element to help the
00035   // iterator.
00036   CurArray[CurArraySize] = 0;
00037 }
00038 
00039 bool SmallPtrSetImpl::insert_imp(const void * Ptr) {
00040   if (isSmall()) {
00041     // Check to see if it is already in the set.
00042     for (const void **APtr = SmallArray, **E = SmallArray+NumElements;
00043          APtr != E; ++APtr)
00044       if (*APtr == Ptr)
00045         return false;
00046     
00047     // Nope, there isn't.  If we stay small, just 'pushback' now.
00048     if (NumElements < CurArraySize-1) {
00049       SmallArray[NumElements++] = Ptr;
00050       return true;
00051     }
00052     // Otherwise, hit the big set case, which will call grow.
00053   }
00054   
00055   // If more than 3/4 of the array is full, grow.
00056   if (NumElements*4 >= CurArraySize*3 ||
00057       CurArraySize-(NumElements+NumTombstones) < CurArraySize/8)
00058     Grow();
00059   
00060   // Okay, we know we have space.  Find a hash bucket.
00061   const void **Bucket = const_cast<const void**>(FindBucketFor(Ptr));
00062   if (*Bucket == Ptr) return false; // Already inserted, good.
00063   
00064   // Otherwise, insert it!
00065   if (*Bucket == getTombstoneMarker())
00066     --NumTombstones;
00067   *Bucket = Ptr;
00068   ++NumElements;  // Track density.
00069   return true;
00070 }
00071 
00072 bool SmallPtrSetImpl::erase_imp(const void * Ptr) {
00073   if (isSmall()) {
00074     // Check to see if it is in the set.
00075     for (const void **APtr = SmallArray, **E = SmallArray+NumElements;
00076          APtr != E; ++APtr)
00077       if (*APtr == Ptr) {
00078         // If it is in the set, replace this element.
00079         *APtr = E[-1];
00080         E[-1] = getEmptyMarker();
00081         --NumElements;
00082         return true;
00083       }
00084     
00085     return false;
00086   }
00087   
00088   // Okay, we know we have space.  Find a hash bucket.
00089   void **Bucket = const_cast<void**>(FindBucketFor(Ptr));
00090   if (*Bucket != Ptr) return false;  // Not in the set?
00091 
00092   // Set this as a tombstone.
00093   *Bucket = getTombstoneMarker();
00094   --NumElements;
00095   ++NumTombstones;
00096   return true;
00097 }
00098 
00099 const void * const *SmallPtrSetImpl::FindBucketFor(const void *Ptr) const {
00100   unsigned Bucket = Hash(Ptr);
00101   unsigned ArraySize = CurArraySize;
00102   unsigned ProbeAmt = 1;
00103   const void *const *Array = CurArray;
00104   const void *const *Tombstone = 0;
00105   while (1) {
00106     // Found Ptr's bucket?
00107     if (Array[Bucket] == Ptr)
00108       return Array+Bucket;
00109     
00110     // If we found an empty bucket, the pointer doesn't exist in the set.
00111     // Return a tombstone if we've seen one so far, or the empty bucket if
00112     // not.
00113     if (Array[Bucket] == getEmptyMarker())
00114       return Tombstone ? Tombstone : Array+Bucket;
00115     
00116     // If this is a tombstone, remember it.  If Ptr ends up not in the set, we
00117     // prefer to return it than something that would require more probing.
00118     if (Array[Bucket] == getTombstoneMarker() && !Tombstone)
00119       Tombstone = Array+Bucket;  // Remember the first tombstone found.
00120     
00121     // It's a hash collision or a tombstone. Reprobe.
00122     Bucket = (Bucket + ProbeAmt++) & (ArraySize-1);
00123   }
00124 }
00125 
00126 /// Grow - Allocate a larger backing store for the buckets and move it over.
00127 ///
00128 void SmallPtrSetImpl::Grow() {
00129   // Allocate at twice as many buckets, but at least 128.
00130   unsigned OldSize = CurArraySize;
00131   unsigned NewSize = OldSize < 64 ? 128 : OldSize*2;
00132   
00133   const void **OldBuckets = CurArray;
00134   bool WasSmall = isSmall();
00135   
00136   // Install the new array.  Clear all the buckets to empty.
00137   CurArray = (const void**)malloc(sizeof(void*) * (NewSize+1));
00138   assert(CurArray && "Failed to allocate memory?");
00139   CurArraySize = NewSize;
00140   memset(CurArray, -1, NewSize*sizeof(void*));
00141   
00142   // The end pointer, always valid, is set to a valid element to help the
00143   // iterator.
00144   CurArray[NewSize] = 0;
00145   
00146   // Copy over all the elements.
00147   if (WasSmall) {
00148     // Small sets store their elements in order.
00149     for (const void **BucketPtr = OldBuckets, **E = OldBuckets+NumElements;
00150          BucketPtr != E; ++BucketPtr) {
00151       const void *Elt = *BucketPtr;
00152       *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt);
00153     }
00154   } else {
00155     // Copy over all valid entries.
00156     for (const void **BucketPtr = OldBuckets, **E = OldBuckets+OldSize;
00157          BucketPtr != E; ++BucketPtr) {
00158       // Copy over the element if it is valid.
00159       const void *Elt = *BucketPtr;
00160       if (Elt != getTombstoneMarker() && Elt != getEmptyMarker())
00161         *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt);
00162     }
00163     
00164     free(OldBuckets);
00165     NumTombstones = 0;
00166   }
00167 }
00168 
00169 SmallPtrSetImpl::SmallPtrSetImpl(const SmallPtrSetImpl& that) {
00170   // If we're becoming small, prepare to insert into our stack space
00171   if (that.isSmall()) {
00172     CurArray = &SmallArray[0];
00173   // Otherwise, allocate new heap space (unless we were the same size)
00174   } else {
00175     CurArray = (const void**)malloc(sizeof(void*) * (that.CurArraySize+1));
00176     assert(CurArray && "Failed to allocate memory?");
00177   }
00178   
00179   // Copy over the new array size
00180   CurArraySize = that.CurArraySize;
00181 
00182   // Copy over the contents from the other set
00183   memcpy(CurArray, that.CurArray, sizeof(void*)*(CurArraySize+1));
00184   
00185   NumElements = that.NumElements;
00186   NumTombstones = that.NumTombstones;
00187 }
00188 
00189 /// CopyFrom - implement operator= from a smallptrset that has the same pointer
00190 /// type, but may have a different small size.
00191 void SmallPtrSetImpl::CopyFrom(const SmallPtrSetImpl &RHS) {
00192   if (isSmall() && RHS.isSmall())
00193     assert(CurArraySize == RHS.CurArraySize &&
00194            "Cannot assign sets with different small sizes");
00195            
00196   // If we're becoming small, prepare to insert into our stack space
00197   if (RHS.isSmall()) {
00198     if (!isSmall())
00199       free(CurArray);
00200     CurArray = &SmallArray[0];
00201   // Otherwise, allocate new heap space (unless we were the same size)
00202   } else if (CurArraySize != RHS.CurArraySize) {
00203     if (isSmall())
00204       CurArray = (const void**)malloc(sizeof(void*) * (RHS.CurArraySize+1));
00205     else
00206       CurArray = (const void**)realloc(CurArray, sizeof(void*)*(RHS.CurArraySize+1));
00207     assert(CurArray && "Failed to allocate memory?");
00208   }
00209   
00210   // Copy over the new array size
00211   CurArraySize = RHS.CurArraySize;
00212 
00213   // Copy over the contents from the other set
00214   memcpy(CurArray, RHS.CurArray, sizeof(void*)*(CurArraySize+1));
00215   
00216   NumElements = RHS.NumElements;
00217   NumTombstones = RHS.NumTombstones;
00218 }
00219 
00220 SmallPtrSetImpl::~SmallPtrSetImpl() {
00221   if (!isSmall())
00222     free(CurArray);
00223 }



This web site is hosted by the Computer Science Department at the University of Illinois at Urbana-Champaign.