mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-02 02:51:42 +00:00
Import llvm::SmallPtrSet.
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#ifndef LLVM_ADT_DENSEMAPINFO_H
|
||||
#define LLVM_ADT_DENSEMAPINFO_H
|
||||
|
||||
#include "llvm/PointerLikeTypeTraits.h"
|
||||
#include "llvm/type_traits.h"
|
||||
|
||||
namespace llvm {
|
||||
@@ -31,12 +32,12 @@ template<typename T>
|
||||
struct DenseMapInfo<T*> {
|
||||
static inline T* getEmptyKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-1);
|
||||
Val <<= 2;
|
||||
Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
|
||||
return reinterpret_cast<T*>(Val);
|
||||
}
|
||||
static inline T* getTombstoneKey() {
|
||||
uintptr_t Val = static_cast<uintptr_t>(-2);
|
||||
Val <<= 2;
|
||||
Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
|
||||
return reinterpret_cast<T*>(Val);
|
||||
}
|
||||
static unsigned getHashValue(const T *PtrVal) {
|
||||
|
||||
81
include/llvm/PointerLikeTypeTraits.h
Normal file
81
include/llvm/PointerLikeTypeTraits.h
Normal file
@@ -0,0 +1,81 @@
|
||||
//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the PointerLikeTypeTraits class. This allows data
|
||||
// structures to reason about pointers and other things that are pointer sized.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
|
||||
#define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// PointerLikeTypeTraits - This is a traits object that is used to handle
|
||||
/// pointer types and things that are just wrappers for pointers as a uniform
|
||||
/// entity.
|
||||
template <typename T>
|
||||
class PointerLikeTypeTraits {
|
||||
// getAsVoidPointer
|
||||
// getFromVoidPointer
|
||||
// getNumLowBitsAvailable
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for non-cvr pointers.
|
||||
template<typename T>
|
||||
class PointerLikeTypeTraits<T*> {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(T* P) { return P; }
|
||||
static inline T *getFromVoidPointer(void *P) {
|
||||
return static_cast<T*>(P);
|
||||
}
|
||||
|
||||
/// Note, we assume here that malloc returns objects at least 4-byte aligned.
|
||||
/// However, this may be wrong, or pointers may be from something other than
|
||||
/// malloc. In this case, you should specialize this template to reduce this.
|
||||
///
|
||||
/// All clients should use assertions to do a run-time check to ensure that
|
||||
/// this is actually true.
|
||||
enum { NumLowBitsAvailable = 2 };
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for const pointers.
|
||||
template<typename T>
|
||||
class PointerLikeTypeTraits<const T*> {
|
||||
typedef PointerLikeTypeTraits<T*> NonConst;
|
||||
|
||||
public:
|
||||
static inline const void *getAsVoidPointer(const T* P) {
|
||||
return NonConst::getAsVoidPointer(const_cast<T*>(P));
|
||||
}
|
||||
static inline const T *getFromVoidPointer(const void *P) {
|
||||
return NonConst::getFromVoidPointer(const_cast<void*>(P));
|
||||
}
|
||||
enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
|
||||
};
|
||||
|
||||
// Provide PointerLikeTypeTraits for uintptr_t.
|
||||
template<>
|
||||
class PointerLikeTypeTraits<uintptr_t> {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(uintptr_t P) {
|
||||
return reinterpret_cast<void*>(P);
|
||||
}
|
||||
static inline uintptr_t getFromVoidPointer(void *P) {
|
||||
return reinterpret_cast<uintptr_t>(P);
|
||||
}
|
||||
// No bits are available!
|
||||
enum { NumLowBitsAvailable = 0 };
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
346
include/llvm/SmallPtrSet.h
Normal file
346
include/llvm/SmallPtrSet.h
Normal file
@@ -0,0 +1,346 @@
|
||||
//===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SmallPtrSet class. See the doxygen comment for
|
||||
// SmallPtrSetImplBase for more details on the algorithm used.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_ADT_SMALLPTRSET_H
|
||||
#define LLVM_ADT_SMALLPTRSET_H
|
||||
|
||||
#include "llvm/Compiler.h"
|
||||
#include "llvm/PointerLikeTypeTraits.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class SmallPtrSetIteratorImpl;
|
||||
|
||||
/// SmallPtrSetImplBase - This is the common code shared among all the
|
||||
/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one
|
||||
/// for small and one for large sets.
|
||||
///
|
||||
/// Small sets use an array of pointers allocated in the SmallPtrSet object,
|
||||
/// which is treated as a simple array of pointers. When a pointer is added to
|
||||
/// the set, the array is scanned to see if the element already exists, if not
|
||||
/// the element is 'pushed back' onto the array. If we run out of space in the
|
||||
/// array, we grow into the 'large set' case. SmallSet should be used when the
|
||||
/// sets are often small. In this case, no memory allocation is used, and only
|
||||
/// light-weight and cache-efficient scanning is used.
|
||||
///
|
||||
/// Large sets use a classic exponentially-probed hash table. Empty buckets are
|
||||
/// represented with an illegal pointer value (-1) to allow null pointers to be
|
||||
/// inserted. Tombstones are represented with another illegal pointer value
|
||||
/// (-2), to allow deletion. The hash table is resized when the table is 3/4 or
|
||||
/// more. When this happens, the table is doubled in size.
|
||||
///
|
||||
class SmallPtrSetImplBase {
|
||||
friend class SmallPtrSetIteratorImpl;
|
||||
protected:
|
||||
/// SmallArray - Points to a fixed size set of buckets, used in 'small mode'.
|
||||
const void **SmallArray;
|
||||
/// CurArray - This is the current set of buckets. If equal to SmallArray,
|
||||
/// then the set is in 'small mode'.
|
||||
const void **CurArray;
|
||||
/// CurArraySize - The allocated size of CurArray, always a power of two.
|
||||
unsigned CurArraySize;
|
||||
|
||||
// If small, this is # elts allocated consecutively
|
||||
unsigned NumElements;
|
||||
unsigned NumTombstones;
|
||||
|
||||
// Helpers to copy and move construct a SmallPtrSet.
|
||||
SmallPtrSetImplBase(const void **SmallStorage, const SmallPtrSetImplBase &that);
|
||||
SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize,
|
||||
SmallPtrSetImplBase &&that);
|
||||
explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize) :
|
||||
SmallArray(SmallStorage), CurArray(SmallStorage), CurArraySize(SmallSize) {
|
||||
assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 &&
|
||||
"Initial size must be a power of two!");
|
||||
clear();
|
||||
}
|
||||
~SmallPtrSetImplBase();
|
||||
|
||||
public:
|
||||
typedef unsigned size_type;
|
||||
bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return size() == 0; }
|
||||
size_type size() const { return NumElements; }
|
||||
|
||||
void clear() {
|
||||
// If the capacity of the array is huge, and the # elements used is small,
|
||||
// shrink the array.
|
||||
if (!isSmall() && NumElements*4 < CurArraySize && CurArraySize > 32)
|
||||
return shrink_and_clear();
|
||||
|
||||
// Fill the array with empty markers.
|
||||
memset(CurArray, -1, CurArraySize*sizeof(void*));
|
||||
NumElements = 0;
|
||||
NumTombstones = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
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);
|
||||
}
|
||||
|
||||
/// insert_imp - This returns true if the pointer was new to the set, false if
|
||||
/// it was already in the set. This is hidden from the client so that the
|
||||
/// derived class can check that the right type of pointer is passed in.
|
||||
std::pair<const void *const *, bool> insert_imp(const void *Ptr);
|
||||
|
||||
/// erase_imp - If the set contains the specified pointer, remove it and
|
||||
/// return true, otherwise return false. This is hidden from the client so
|
||||
/// that the derived class can check that the right type of pointer is passed
|
||||
/// in.
|
||||
bool erase_imp(const void * Ptr);
|
||||
|
||||
bool count_imp(const void * Ptr) const {
|
||||
if (isSmall()) {
|
||||
// Linear search for the item.
|
||||
for (const 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:
|
||||
bool isSmall() const { return CurArray == SmallArray; }
|
||||
|
||||
const void * const *FindBucketFor(const void *Ptr) const;
|
||||
void shrink_and_clear();
|
||||
|
||||
/// Grow - Allocate a larger backing store for the buckets and move it over.
|
||||
void Grow(unsigned NewSize);
|
||||
|
||||
void operator=(const SmallPtrSetImplBase &RHS) = delete;
|
||||
protected:
|
||||
/// swap - Swaps the elements of two sets.
|
||||
/// Note: This method assumes that both sets have the same small size.
|
||||
void swap(SmallPtrSetImplBase &RHS);
|
||||
|
||||
void CopyFrom(const SmallPtrSetImplBase &RHS);
|
||||
void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS);
|
||||
};
|
||||
|
||||
/// SmallPtrSetIteratorImpl - This is the common base class shared between all
|
||||
/// instances of SmallPtrSetIterator.
|
||||
class SmallPtrSetIteratorImpl {
|
||||
protected:
|
||||
const void *const *Bucket;
|
||||
const void *const *End;
|
||||
public:
|
||||
explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
|
||||
: Bucket(BP), End(E) {
|
||||
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() {
|
||||
assert(Bucket <= End);
|
||||
while (Bucket != End &&
|
||||
(*Bucket == SmallPtrSetImplBase::getEmptyMarker() ||
|
||||
*Bucket == SmallPtrSetImplBase::getTombstoneMarker()))
|
||||
++Bucket;
|
||||
}
|
||||
};
|
||||
|
||||
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
|
||||
template<typename PtrTy>
|
||||
class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
|
||||
typedef PointerLikeTypeTraits<PtrTy> PtrTraits;
|
||||
|
||||
public:
|
||||
typedef PtrTy value_type;
|
||||
typedef PtrTy reference;
|
||||
typedef PtrTy pointer;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
|
||||
: SmallPtrSetIteratorImpl(BP, E) {}
|
||||
|
||||
// Most methods provided by baseclass.
|
||||
|
||||
const PtrTy operator*() const {
|
||||
assert(Bucket < End);
|
||||
return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket));
|
||||
}
|
||||
|
||||
inline SmallPtrSetIterator& operator++() { // Preincrement
|
||||
++Bucket;
|
||||
AdvanceIfNotValid();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSetIterator operator++(int) { // Postincrement
|
||||
SmallPtrSetIterator tmp = *this; ++*this; return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
/// RoundUpToPowerOfTwo - This is a helper template that rounds N up to the next
|
||||
/// power of two (which means N itself if N is already a power of two).
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwo;
|
||||
|
||||
/// RoundUpToPowerOfTwoH - If N is not a power of two, increase it. This is a
|
||||
/// helper template used to implement RoundUpToPowerOfTwo.
|
||||
template<unsigned N, bool isPowerTwo>
|
||||
struct RoundUpToPowerOfTwoH {
|
||||
enum { Val = N };
|
||||
};
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwoH<N, false> {
|
||||
enum {
|
||||
// We could just use NextVal = N+1, but this converges faster. N|(N-1) sets
|
||||
// the right-most zero bits to one all at once, e.g. 0b0011000 -> 0b0011111.
|
||||
Val = RoundUpToPowerOfTwo<(N|(N-1)) + 1>::Val
|
||||
};
|
||||
};
|
||||
|
||||
template<unsigned N>
|
||||
struct RoundUpToPowerOfTwo {
|
||||
enum { Val = RoundUpToPowerOfTwoH<N, (N&(N-1)) == 0>::Val };
|
||||
};
|
||||
|
||||
|
||||
/// \brief A templated base class for \c SmallPtrSet which provides the
|
||||
/// typesafe interface that is common across all small sizes.
|
||||
///
|
||||
/// This is particularly useful for passing around between interface boundaries
|
||||
/// to avoid encoding a particular small size in the interface boundary.
|
||||
template <typename PtrType>
|
||||
class SmallPtrSetImpl : public SmallPtrSetImplBase {
|
||||
typedef PointerLikeTypeTraits<PtrType> PtrTraits;
|
||||
|
||||
SmallPtrSetImpl(const SmallPtrSetImpl&) = delete;
|
||||
protected:
|
||||
// Constructors that forward to the base.
|
||||
SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that)
|
||||
: SmallPtrSetImplBase(SmallStorage, that) {}
|
||||
SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize,
|
||||
SmallPtrSetImpl &&that)
|
||||
: SmallPtrSetImplBase(SmallStorage, SmallSize, std::move(that)) {}
|
||||
explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize)
|
||||
: SmallPtrSetImplBase(SmallStorage, SmallSize) {}
|
||||
|
||||
public:
|
||||
typedef SmallPtrSetIterator<PtrType> iterator;
|
||||
typedef SmallPtrSetIterator<PtrType> const_iterator;
|
||||
|
||||
/// Inserts Ptr if and only if there is no element in the container equal to
|
||||
/// Ptr. The bool component of the returned pair is true if and only if the
|
||||
/// insertion takes place, and the iterator component of the pair points to
|
||||
/// the element equal to Ptr.
|
||||
std::pair<iterator, bool> insert(PtrType Ptr) {
|
||||
auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
return std::make_pair(iterator(p.first, CurArray + CurArraySize), p.second);
|
||||
}
|
||||
|
||||
/// erase - If the set contains the specified pointer, remove it and return
|
||||
/// true, otherwise return false.
|
||||
bool erase(PtrType Ptr) {
|
||||
return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
|
||||
}
|
||||
|
||||
/// count - Return 1 if the specified pointer is in the set, 0 otherwise.
|
||||
size_type count(PtrType Ptr) const {
|
||||
return count_imp(PtrTraits::getAsVoidPointer(Ptr)) ? 1 : 0;
|
||||
}
|
||||
|
||||
template <typename IterT>
|
||||
void insert(IterT I, IterT E) {
|
||||
for (; I != E; ++I)
|
||||
insert(*I);
|
||||
}
|
||||
|
||||
inline iterator begin() const {
|
||||
return iterator(CurArray, CurArray+CurArraySize);
|
||||
}
|
||||
inline iterator end() const {
|
||||
return iterator(CurArray+CurArraySize, CurArray+CurArraySize);
|
||||
}
|
||||
};
|
||||
|
||||
/// SmallPtrSet - This class implements a set which is optimized for holding
|
||||
/// SmallSize or less elements. This internally rounds up SmallSize to the next
|
||||
/// power of two if it is not already a power of two. See the comments above
|
||||
/// SmallPtrSetImplBase for details of the algorithm.
|
||||
template<class PtrType, unsigned SmallSize>
|
||||
class SmallPtrSet : public SmallPtrSetImpl<PtrType> {
|
||||
typedef SmallPtrSetImpl<PtrType> BaseT;
|
||||
|
||||
// Make sure that SmallSize is a power of two, round up if not.
|
||||
enum { SmallSizePowTwo = RoundUpToPowerOfTwo<SmallSize>::Val };
|
||||
/// SmallStorage - Fixed size storage used in 'small mode'.
|
||||
const void *SmallStorage[SmallSizePowTwo];
|
||||
public:
|
||||
SmallPtrSet() : BaseT(SmallStorage, SmallSizePowTwo) {}
|
||||
SmallPtrSet(const SmallPtrSet &that) : BaseT(SmallStorage, that) {}
|
||||
SmallPtrSet(SmallPtrSet &&that)
|
||||
: BaseT(SmallStorage, SmallSizePowTwo, std::move(that)) {}
|
||||
|
||||
template<typename It>
|
||||
SmallPtrSet(It I, It E) : BaseT(SmallStorage, SmallSizePowTwo) {
|
||||
this->insert(I, E);
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize> &
|
||||
operator=(const SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
if (&RHS != this)
|
||||
this->CopyFrom(RHS);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SmallPtrSet<PtrType, SmallSize>&
|
||||
operator=(SmallPtrSet<PtrType, SmallSize> &&RHS) {
|
||||
if (&RHS != this)
|
||||
this->MoveFrom(SmallSizePowTwo, std::move(RHS));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// swap - Swaps the elements of two sets.
|
||||
void swap(SmallPtrSet<PtrType, SmallSize> &RHS) {
|
||||
SmallPtrSetImplBase::swap(RHS);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
namespace std {
|
||||
/// Implement std::swap in terms of SmallPtrSet swap.
|
||||
template<class T, unsigned N>
|
||||
inline void swap(llvm::SmallPtrSet<T, N> &LHS, llvm::SmallPtrSet<T, N> &RHS) {
|
||||
LHS.swap(RHS);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
338
src/llvm/SmallPtrSet.cpp
Normal file
338
src/llvm/SmallPtrSet.cpp
Normal file
@@ -0,0 +1,338 @@
|
||||
//===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the SmallPtrSet class. See SmallPtrSet.h for an
|
||||
// overview of the algorithm.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/SmallPtrSet.h"
|
||||
#include "llvm/DenseMapInfo.h"
|
||||
#include "llvm/MathExtras.h"
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
void SmallPtrSetImplBase::shrink_and_clear() {
|
||||
assert(!isSmall() && "Can't shrink a small set!");
|
||||
free(CurArray);
|
||||
|
||||
// Reduce the number of buckets.
|
||||
CurArraySize = NumElements > 16 ? 1 << (Log2_32_Ceil(NumElements) + 1) : 32;
|
||||
NumElements = NumTombstones = 0;
|
||||
|
||||
// Install the new array. Clear all the buckets to empty.
|
||||
CurArray = (const void**)malloc(sizeof(void*) * CurArraySize);
|
||||
assert(CurArray && "Failed to allocate memory?");
|
||||
memset(CurArray, -1, CurArraySize*sizeof(void*));
|
||||
}
|
||||
|
||||
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)) {
|
||||
// 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)) {
|
||||
// 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)
|
||||
return std::make_pair(Bucket, false); // Already inserted, good.
|
||||
|
||||
// Otherwise, insert it!
|
||||
if (*Bucket == getTombstoneMarker())
|
||||
--NumTombstones;
|
||||
*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)
|
||||
if (*APtr == Ptr) {
|
||||
// If it is in the set, replace this element.
|
||||
*APtr = E[-1];
|
||||
E[-1] = getEmptyMarker();
|
||||
--NumElements;
|
||||
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;
|
||||
}
|
||||
|
||||
const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const {
|
||||
unsigned Bucket = DenseMapInfo<void *>::getHashValue(Ptr) & (CurArraySize-1);
|
||||
unsigned ArraySize = CurArraySize;
|
||||
unsigned ProbeAmt = 1;
|
||||
const void *const *Array = CurArray;
|
||||
const void *const *Tombstone = nullptr;
|
||||
while (1) {
|
||||
// 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 (LLVM_LIKELY(Array[Bucket] == getEmptyMarker()))
|
||||
return Tombstone ? Tombstone : Array+Bucket;
|
||||
|
||||
// Found Ptr's bucket?
|
||||
if (LLVM_LIKELY(Array[Bucket] == Ptr))
|
||||
return 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 SmallPtrSetImplBase::Grow(unsigned NewSize) {
|
||||
// Allocate at twice as many buckets, but at least 128.
|
||||
unsigned OldSize = CurArraySize;
|
||||
|
||||
const void **OldBuckets = CurArray;
|
||||
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;
|
||||
*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;
|
||||
}
|
||||
}
|
||||
|
||||
SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage,
|
||||
const SmallPtrSetImplBase& that) {
|
||||
SmallArray = SmallStorage;
|
||||
|
||||
// If we're becoming small, prepare to insert into our stack space
|
||||
if (that.isSmall()) {
|
||||
CurArray = SmallArray;
|
||||
// Otherwise, allocate new heap space (unless we were the same size)
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// 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.");
|
||||
|
||||
if (isSmall() && RHS.isSmall())
|
||||
assert(CurArraySize == RHS.CurArraySize &&
|
||||
"Cannot assign sets with different small sizes");
|
||||
|
||||
// If we're becoming small, prepare to insert into our stack space
|
||||
if (RHS.isSmall()) {
|
||||
if (!isSmall())
|
||||
free(CurArray);
|
||||
CurArray = SmallArray;
|
||||
// Otherwise, allocate new heap space (unless we were the same size)
|
||||
} else if (CurArraySize != RHS.CurArraySize) {
|
||||
if (isSmall())
|
||||
CurArray = (const void**)malloc(sizeof(void*) * RHS.CurArraySize);
|
||||
else {
|
||||
const void **T = (const void**)realloc(CurArray,
|
||||
sizeof(void*) * RHS.CurArraySize);
|
||||
if (!T)
|
||||
free(CurArray);
|
||||
CurArray = T;
|
||||
}
|
||||
assert(CurArray && "Failed to allocate memory?");
|
||||
}
|
||||
|
||||
// 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;
|
||||
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);
|
||||
|
||||
if (RHS.isSmall()) {
|
||||
// Copy a small RHS rather than moving.
|
||||
CurArray = SmallArray;
|
||||
memcpy(CurArray, RHS.CurArray, sizeof(void*)*RHS.CurArraySize);
|
||||
} else {
|
||||
CurArray = RHS.CurArray;
|
||||
RHS.CurArray = RHS.SmallArray;
|
||||
}
|
||||
|
||||
// Copy the rest of the trivial members.
|
||||
CurArraySize = RHS.CurArraySize;
|
||||
NumElements = RHS.NumElements;
|
||||
NumTombstones = RHS.NumTombstones;
|
||||
|
||||
// Make the RHS small and empty.
|
||||
RHS.CurArraySize = SmallSize;
|
||||
assert(RHS.CurArray == RHS.SmallArray);
|
||||
RHS.NumElements = 0;
|
||||
RHS.NumTombstones = 0;
|
||||
}
|
||||
|
||||
void SmallPtrSetImplBase::swap(SmallPtrSetImplBase &RHS) {
|
||||
if (this == &RHS) return;
|
||||
|
||||
// We can only avoid copying elements if neither set is small.
|
||||
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->NumTombstones, RHS.NumTombstones);
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: From here on we assume that both sets have the same small size.
|
||||
|
||||
// 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);
|
||||
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,
|
||||
RHS.SmallArray);
|
||||
std::swap(RHS.NumElements, this->NumElements);
|
||||
std::swap(RHS.CurArraySize, this->CurArraySize);
|
||||
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,
|
||||
RHS.SmallArray);
|
||||
std::swap(this->NumElements, RHS.NumElements);
|
||||
}
|
||||
|
||||
SmallPtrSetImplBase::~SmallPtrSetImplBase() {
|
||||
if (!isSmall())
|
||||
free(CurArray);
|
||||
}
|
||||
Reference in New Issue
Block a user