diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:41:05 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:41:05 +0000 | 
| commit | 01095a5d43bbfde13731688ddcf6048ebb8b7721 (patch) | |
| tree | 4def12e759965de927d963ac65840d663ef9d1ea /lib/Support/SmallPtrSet.cpp | |
| parent | f0f4822ed4b66e3579e92a89f368f8fb860e218e (diff) | |
Notes
Diffstat (limited to 'lib/Support/SmallPtrSet.cpp')
| -rw-r--r-- | lib/Support/SmallPtrSet.cpp | 191 | 
1 files changed, 74 insertions, 117 deletions
| diff --git a/lib/Support/SmallPtrSet.cpp b/lib/Support/SmallPtrSet.cpp index 358c8e8abbe91..539b4eb34da15 100644 --- a/lib/Support/SmallPtrSet.cpp +++ b/lib/Support/SmallPtrSet.cpp @@ -25,8 +25,9 @@ void SmallPtrSetImplBase::shrink_and_clear() {    free(CurArray);    // Reduce the number of buckets. -  CurArraySize = NumElements > 16 ? 1 << (Log2_32_Ceil(NumElements) + 1) : 32; -  NumElements = NumTombstones = 0; +  unsigned Size = size(); +  CurArraySize = Size > 16 ? 1 << (Log2_32_Ceil(Size) + 1) : 32; +  NumNonEmpty = NumTombstones = 0;    // Install the new array.  Clear all the buckets to empty.    CurArray = (const void**)malloc(sizeof(void*) * CurArraySize); @@ -35,32 +36,16 @@ void SmallPtrSetImplBase::shrink_and_clear() {  }  std::pair<const void *const *, bool> -SmallPtrSetImplBase::insert_imp(const void *Ptr) { -  if (isSmall()) { -    // Check to see if it is already in the set. -    for (const void **APtr = SmallArray, **E = SmallArray+NumElements; -         APtr != E; ++APtr) -      if (*APtr == Ptr) -        return std::make_pair(APtr, false); - -    // Nope, there isn't.  If we stay small, just 'pushback' now. -    if (NumElements < CurArraySize) { -      SmallArray[NumElements++] = Ptr; -      return std::make_pair(SmallArray + (NumElements - 1), true); -    } -    // Otherwise, hit the big set case, which will call grow. -  } - -  if (LLVM_UNLIKELY(NumElements * 4 >= CurArraySize * 3)) { +SmallPtrSetImplBase::insert_imp_big(const void *Ptr) { +  if (LLVM_UNLIKELY(size() * 4 >= CurArraySize * 3)) {      // If more than 3/4 of the array is full, grow. -    Grow(CurArraySize < 64 ? 128 : CurArraySize*2); -  } else if (LLVM_UNLIKELY(CurArraySize - (NumElements + NumTombstones) < -                           CurArraySize / 8)) { +    Grow(CurArraySize < 64 ? 128 : CurArraySize * 2); +  } else if (LLVM_UNLIKELY(CurArraySize - NumNonEmpty < CurArraySize / 8)) {      // If fewer of 1/8 of the array is empty (meaning that many are filled with      // tombstones), rehash.      Grow(CurArraySize);    } -   +    // Okay, we know we have space.  Find a hash bucket.    const void **Bucket = const_cast<const void**>(FindBucketFor(Ptr));    if (*Bucket == Ptr) @@ -69,34 +54,33 @@ SmallPtrSetImplBase::insert_imp(const void *Ptr) {    // Otherwise, insert it!    if (*Bucket == getTombstoneMarker())      --NumTombstones; +  else +    ++NumNonEmpty; // Track density.    *Bucket = Ptr; -  ++NumElements;  // Track density.    return std::make_pair(Bucket, true);  }  bool SmallPtrSetImplBase::erase_imp(const void * Ptr) {    if (isSmall()) {      // Check to see if it is in the set. -    for (const void **APtr = SmallArray, **E = SmallArray+NumElements; -         APtr != E; ++APtr) +    for (const void **APtr = CurArray, **E = CurArray + NumNonEmpty; APtr != E; +         ++APtr)        if (*APtr == Ptr) {          // If it is in the set, replace this element. -        *APtr = E[-1]; -        E[-1] = getEmptyMarker(); -        --NumElements; +        *APtr = getTombstoneMarker(); +        ++NumTombstones;          return true;        } -     +      return false;    } -   +    // Okay, we know we have space.  Find a hash bucket.    void **Bucket = const_cast<void**>(FindBucketFor(Ptr));    if (*Bucket != Ptr) return false;  // Not in the set?    // Set this as a tombstone.    *Bucket = getTombstoneMarker(); -  --NumElements;    ++NumTombstones;    return true;  } @@ -122,7 +106,7 @@ const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const {      // 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);    } @@ -131,43 +115,32 @@ const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const {  /// Grow - Allocate a larger backing store for the buckets and move it over.  ///  void SmallPtrSetImplBase::Grow(unsigned NewSize) { -  // Allocate at twice as many buckets, but at least 128. -  unsigned OldSize = CurArraySize; -      const void **OldBuckets = CurArray; +  const void **OldEnd = EndPointer();    bool WasSmall = isSmall(); -   +    // Install the new array.  Clear all the buckets to empty.    CurArray = (const void**)malloc(sizeof(void*) * NewSize);    assert(CurArray && "Failed to allocate memory?");    CurArraySize = NewSize;    memset(CurArray, -1, NewSize*sizeof(void*)); -   -  // Copy over all the elements. -  if (WasSmall) { -    // Small sets store their elements in order. -    for (const void **BucketPtr = OldBuckets, **E = OldBuckets+NumElements; -         BucketPtr != E; ++BucketPtr) { -      const void *Elt = *BucketPtr; + +  // Copy over all valid entries. +  for (const void **BucketPtr = OldBuckets; BucketPtr != OldEnd; ++BucketPtr) { +    // Copy over the element if it is valid. +    const void *Elt = *BucketPtr; +    if (Elt != getTombstoneMarker() && Elt != getEmptyMarker())        *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt); -    } -  } else { -    // Copy over all valid entries. -    for (const void **BucketPtr = OldBuckets, **E = OldBuckets+OldSize; -         BucketPtr != E; ++BucketPtr) { -      // Copy over the element if it is valid. -      const void *Elt = *BucketPtr; -      if (Elt != getTombstoneMarker() && Elt != getEmptyMarker()) -        *const_cast<void**>(FindBucketFor(Elt)) = const_cast<void*>(Elt); -    } -     -    free(OldBuckets); -    NumTombstones = 0;    } + +  if (!WasSmall) +    free(OldBuckets); +  NumNonEmpty -= NumTombstones; +  NumTombstones = 0;  }  SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage, -                                 const SmallPtrSetImplBase& that) { +                                         const SmallPtrSetImplBase &that) {    SmallArray = SmallStorage;    // If we're becoming small, prepare to insert into our stack space @@ -178,46 +151,18 @@ SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,      CurArray = (const void**)malloc(sizeof(void*) * that.CurArraySize);      assert(CurArray && "Failed to allocate memory?");    } -   -  // Copy over the new array size -  CurArraySize = that.CurArraySize; -  // Copy over the contents from the other set -  memcpy(CurArray, that.CurArray, sizeof(void*)*CurArraySize); -   -  NumElements = that.NumElements; -  NumTombstones = that.NumTombstones; +  // Copy over the that array. +  CopyHelper(that);  }  SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,                                           unsigned SmallSize,                                           SmallPtrSetImplBase &&that) {    SmallArray = SmallStorage; - -  // Copy over the basic members. -  CurArraySize = that.CurArraySize; -  NumElements = that.NumElements; -  NumTombstones = that.NumTombstones; - -  // When small, just copy into our small buffer. -  if (that.isSmall()) { -    CurArray = SmallArray; -    memcpy(CurArray, that.CurArray, sizeof(void *) * CurArraySize); -  } else { -    // Otherwise, we steal the large memory allocation and no copy is needed. -    CurArray = that.CurArray; -    that.CurArray = that.SmallArray; -  } - -  // Make the "that" object small and empty. -  that.CurArraySize = SmallSize; -  assert(that.CurArray == that.SmallArray); -  that.NumElements = 0; -  that.NumTombstones = 0; +  MoveHelper(SmallSize, std::move(that));  } -/// CopyFrom - implement operator= from a smallptrset that has the same pointer -/// type, but may have a different small size.  void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) {    assert(&RHS != this && "Self-copy should be handled by the caller."); @@ -243,28 +188,36 @@ void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) {      }      assert(CurArray && "Failed to allocate memory?");    } -   + +  CopyHelper(RHS); +} + +void SmallPtrSetImplBase::CopyHelper(const SmallPtrSetImplBase &RHS) {    // Copy over the new array size    CurArraySize = RHS.CurArraySize;    // Copy over the contents from the other set -  memcpy(CurArray, RHS.CurArray, sizeof(void*)*CurArraySize); -   -  NumElements = RHS.NumElements; +  std::copy(RHS.CurArray, RHS.EndPointer(), CurArray); + +  NumNonEmpty = RHS.NumNonEmpty;    NumTombstones = RHS.NumTombstones;  }  void SmallPtrSetImplBase::MoveFrom(unsigned SmallSize,                                     SmallPtrSetImplBase &&RHS) { -  assert(&RHS != this && "Self-move should be handled by the caller."); -    if (!isSmall())      free(CurArray); +  MoveHelper(SmallSize, std::move(RHS)); +} + +void SmallPtrSetImplBase::MoveHelper(unsigned SmallSize, +                                     SmallPtrSetImplBase &&RHS) { +  assert(&RHS != this && "Self-move should be handled by the caller.");    if (RHS.isSmall()) {      // Copy a small RHS rather than moving.      CurArray = SmallArray; -    memcpy(CurArray, RHS.CurArray, sizeof(void*)*RHS.CurArraySize); +    std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, CurArray);    } else {      CurArray = RHS.CurArray;      RHS.CurArray = RHS.SmallArray; @@ -272,13 +225,13 @@ void SmallPtrSetImplBase::MoveFrom(unsigned SmallSize,    // Copy the rest of the trivial members.    CurArraySize = RHS.CurArraySize; -  NumElements = RHS.NumElements; +  NumNonEmpty = RHS.NumNonEmpty;    NumTombstones = RHS.NumTombstones;    // Make the RHS small and empty.    RHS.CurArraySize = SmallSize;    assert(RHS.CurArray == RHS.SmallArray); -  RHS.NumElements = 0; +  RHS.NumNonEmpty = 0;    RHS.NumTombstones = 0;  } @@ -289,7 +242,7 @@ void SmallPtrSetImplBase::swap(SmallPtrSetImplBase &RHS) {    if (!this->isSmall() && !RHS.isSmall()) {      std::swap(this->CurArray, RHS.CurArray);      std::swap(this->CurArraySize, RHS.CurArraySize); -    std::swap(this->NumElements, RHS.NumElements); +    std::swap(this->NumNonEmpty, RHS.NumNonEmpty);      std::swap(this->NumTombstones, RHS.NumTombstones);      return;    } @@ -299,40 +252,44 @@ void SmallPtrSetImplBase::swap(SmallPtrSetImplBase &RHS) {    // If only RHS is small, copy the small elements into LHS and move the pointer    // from LHS to RHS.    if (!this->isSmall() && RHS.isSmall()) { -    std::copy(RHS.SmallArray, RHS.SmallArray+RHS.CurArraySize, -              this->SmallArray); -    std::swap(this->NumElements, RHS.NumElements); -    std::swap(this->CurArraySize, RHS.CurArraySize); +    assert(RHS.CurArray == RHS.SmallArray); +    std::copy(RHS.CurArray, RHS.CurArray + RHS.NumNonEmpty, this->SmallArray); +    std::swap(RHS.CurArraySize, this->CurArraySize); +    std::swap(this->NumNonEmpty, RHS.NumNonEmpty); +    std::swap(this->NumTombstones, RHS.NumTombstones);      RHS.CurArray = this->CurArray; -    RHS.NumTombstones = this->NumTombstones;      this->CurArray = this->SmallArray; -    this->NumTombstones = 0;      return;    }    // If only LHS is small, copy the small elements into RHS and move the pointer    // from RHS to LHS.    if (this->isSmall() && !RHS.isSmall()) { -    std::copy(this->SmallArray, this->SmallArray+this->CurArraySize, +    assert(this->CurArray == this->SmallArray); +    std::copy(this->CurArray, this->CurArray + this->NumNonEmpty,                RHS.SmallArray); -    std::swap(RHS.NumElements, this->NumElements);      std::swap(RHS.CurArraySize, this->CurArraySize); +    std::swap(RHS.NumNonEmpty, this->NumNonEmpty); +    std::swap(RHS.NumTombstones, this->NumTombstones);      this->CurArray = RHS.CurArray; -    this->NumTombstones = RHS.NumTombstones;      RHS.CurArray = RHS.SmallArray; -    RHS.NumTombstones = 0;      return;    }    // Both a small, just swap the small elements.    assert(this->isSmall() && RHS.isSmall()); -  assert(this->CurArraySize == RHS.CurArraySize); -  std::swap_ranges(this->SmallArray, this->SmallArray+this->CurArraySize, +  unsigned MinNonEmpty = std::min(this->NumNonEmpty, RHS.NumNonEmpty); +  std::swap_ranges(this->SmallArray, this->SmallArray + MinNonEmpty,                     RHS.SmallArray); -  std::swap(this->NumElements, RHS.NumElements); -} - -SmallPtrSetImplBase::~SmallPtrSetImplBase() { -  if (!isSmall()) -    free(CurArray); +  if (this->NumNonEmpty > MinNonEmpty) { +    std::copy(this->SmallArray + MinNonEmpty, +              this->SmallArray + this->NumNonEmpty, +              RHS.SmallArray + MinNonEmpty); +  } else { +    std::copy(RHS.SmallArray + MinNonEmpty, RHS.SmallArray + RHS.NumNonEmpty, +              this->SmallArray + MinNonEmpty); +  } +  assert(this->CurArraySize == RHS.CurArraySize); +  std::swap(this->NumNonEmpty, RHS.NumNonEmpty); +  std::swap(this->NumTombstones, RHS.NumTombstones);  } | 
