Skip to content

Commit

Permalink
[NFC] More cherry picks in preparation of ReverseIterator changes (mi…
Browse files Browse the repository at this point in the history
…crosoft#5340)

Continuing work from
microsoft#5329

Another 2 cherry picks. Bit bigger this time, but no changes required
apart from the free->delete change as before

---------

Co-authored-by: Matthias Braun <[email protected]>
Co-authored-by: Benjamin Kramer <[email protected]>
  • Loading branch information
3 people authored Jun 28, 2023
1 parent a35f1fa commit c462faa
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 108 deletions.
90 changes: 60 additions & 30 deletions include/llvm/ADT/DenseMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,30 +167,65 @@ class DenseMapBase : public DebugEpochBase {
// If the key is already in the map, it returns false and doesn't update the
// value.
std::pair<iterator, bool> insert(const std::pair<KeyT, ValueT> &KV) {
return try_emplace(KV.first, KV.second);
}

// Inserts key,value pair into the map if the key isn't already in the map.
// If the key is already in the map, it returns false and doesn't update the
// value.
std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
return try_emplace(std::move(KV.first), std::move(KV.second));
}

// Inserts key,value pair into the map if the key isn't already in the map.
// The value is constructed in-place if the key is not in the map, otherwise
// it is not moved.
template <typename... Ts>
std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(KV.first, TheBucket))
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.

// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket);
TheBucket =
InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
true);
}

// Inserts key,value pair into the map if the key isn't already in the map.
// If the key is already in the map, it returns false and doesn't update the
// value.
std::pair<iterator, bool> insert(std::pair<KeyT, ValueT> &&KV) {
// The value is constructed in-place if the key is not in the map, otherwise
// it is not moved.
template <typename... Ts>
std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.

// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
true);
}

/// Alternate version of insert() which allows a different, and possibly
/// less expensive, key type.
/// The DenseMapInfo is responsible for supplying methods
/// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key
/// type used.
template <typename LookupKeyT>
std::pair<iterator, bool> insert_as(std::pair<KeyT, ValueT> &&KV,
const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(KV.first, TheBucket))
if (LookupBucketFor(Val, TheBucket))
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
false); // Already in map.

// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(std::move(KV.first),
std::move(KV.second),
TheBucket);
TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
std::move(KV.second), Val);
return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true),
true);
}
Expand Down Expand Up @@ -227,7 +262,7 @@ class DenseMapBase : public DebugEpochBase {
if (LookupBucketFor(Key, TheBucket))
return *TheBucket;

return *InsertIntoBucket(Key, ValueT(), TheBucket);
return *InsertIntoBucket(TheBucket, Key);
}

ValueT &operator[](const KeyT &Key) {
Expand All @@ -239,7 +274,7 @@ class DenseMapBase : public DebugEpochBase {
if (LookupBucketFor(Key, TheBucket))
return *TheBucket;

return *InsertIntoBucket(std::move(Key), ValueT(), TheBucket);
return *InsertIntoBucket(TheBucket, std::move(Key));
}

ValueT &operator[](KeyT &&Key) {
Expand Down Expand Up @@ -396,34 +431,29 @@ class DenseMapBase : public DebugEpochBase {
static_cast<DerivedT *>(this)->shrink_and_clear();
}

template <typename KeyArg, typename... ValueArgs>
BucketT *InsertIntoBucket(BucketT *TheBucket, KeyArg &&Key,
ValueArgs &&... Values) {
TheBucket = InsertIntoBucketImpl(Key, Key, TheBucket);

BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value,
BucketT *TheBucket) {
TheBucket = InsertIntoBucketImpl(Key, TheBucket);

TheBucket->getFirst() = Key;
new (&TheBucket->getSecond()) ValueT(Value);
TheBucket->getFirst() = std::forward<KeyArg>(Key);
::new (&TheBucket->getSecond()) ValueT(std::forward<ValueArgs>(Values)...);
return TheBucket;
}

BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value,
BucketT *TheBucket) {
TheBucket = InsertIntoBucketImpl(Key, TheBucket);

TheBucket->getFirst() = Key;
new (&TheBucket->getSecond()) ValueT(std::move(Value));
return TheBucket;
}

BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) {
TheBucket = InsertIntoBucketImpl(Key, TheBucket);
template <typename LookupKeyT>
BucketT *InsertIntoBucketWithLookup(BucketT *TheBucket, KeyT &&Key,
ValueT &&Value, LookupKeyT &Lookup) {
TheBucket = InsertIntoBucketImpl(Key, Lookup, TheBucket);

TheBucket->getFirst() = std::move(Key);
new (&TheBucket->getSecond()) ValueT(std::move(Value));
::new (&TheBucket->getSecond()) ValueT(std::move(Value));
return TheBucket;
}

BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) {
template <typename LookupKeyT>
BucketT *InsertIntoBucketImpl(const KeyT &Key, const LookupKeyT &Lookup,
BucketT *TheBucket) {
incrementEpoch();

// If the load of the hash table is more than 3/4, or if fewer than 1/8 of
Expand Down
66 changes: 44 additions & 22 deletions include/llvm/ADT/SmallPtrSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,36 +57,41 @@ class SmallPtrSetImplBase {
/// CurArraySize - The allocated size of CurArray, always a power of two.
unsigned CurArraySize;

// If small, this is # elts allocated consecutively
unsigned NumElements;
/// Number of elements in CurArray that contain a value or are a tombstone.
/// If small, all these elements are at the beginning of CurArray and the rest
/// is uninitialized.
unsigned NumNonEmpty;
/// Number of tombstones in CurArray.
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) {
SmallPtrSetImplBase &&that);
explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize)
: SmallArray(SmallStorage), CurArray(SmallStorage),
CurArraySize(SmallSize), NumNonEmpty(0), NumTombstones(0) {
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; }
size_type size() const { return NumNonEmpty - NumTombstones; }

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();
if (!isSmall()) {
if (size() * 4 < CurArraySize && CurArraySize > 32)
return shrink_and_clear();
// Fill the array with empty markers.
memset(CurArray, -1, CurArraySize * sizeof(void *));
}

// Fill the array with empty markers.
memset(CurArray, -1, CurArraySize*sizeof(void*));
NumElements = 0;
NumNonEmpty = 0;
NumTombstones = 0;
}

Expand All @@ -98,21 +103,37 @@ class SmallPtrSetImplBase {
return reinterpret_cast<void*>(-1);
}

const void **EndPointer() const {
return isSmall() ? CurArray + NumNonEmpty : CurArray + CurArraySize;
}

/// 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) {
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)
const void **LastTombstone = nullptr;
for (const void **APtr = SmallArray, **E = SmallArray + NumNonEmpty;
APtr != E; ++APtr) {
const void *Value = *APtr;
if (Value == Ptr)
return std::make_pair(APtr, false);
if (Value == getTombstoneMarker())
LastTombstone = APtr;
}

// Did we find any tombstone marker?
if (LastTombstone != nullptr) {
*LastTombstone = Ptr;
--NumTombstones;
return std::make_pair(LastTombstone, true);
}

// 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);
if (NumNonEmpty < CurArraySize) {
SmallArray[NumNonEmpty++] = Ptr;
return std::make_pair(SmallArray + (NumNonEmpty - 1), true);
}
// Otherwise, hit the big set case, which will call grow.
}
Expand All @@ -129,7 +150,7 @@ class SmallPtrSetImplBase {
if (isSmall()) {
// Linear search for the item.
for (const void *const *APtr = SmallArray,
*const *E = SmallArray+NumElements; APtr != E; ++APtr)
*const *E = SmallArray + NumNonEmpty; APtr != E; ++APtr)
if (*APtr == Ptr)
return true;
return false;
Expand Down Expand Up @@ -287,7 +308,7 @@ class SmallPtrSetImpl : public SmallPtrSetImplBase {
/// 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);
return std::make_pair(iterator(p.first, EndPointer()), p.second);
}

/// erase - If the set contains the specified pointer, remove it and return
Expand All @@ -308,10 +329,11 @@ class SmallPtrSetImpl : public SmallPtrSetImplBase {
}

inline iterator begin() const {
return iterator(CurArray, CurArray+CurArraySize);
return iterator(CurArray, EndPointer());
}
inline iterator end() const {
return iterator(CurArray+CurArraySize, CurArray+CurArraySize);
const void *const *End = EndPointer();
return iterator(End, End);
}
};

Expand Down
Loading

0 comments on commit c462faa

Please sign in to comment.