[wpiutil] Reduce llvm collections patches (#4268)

This commit is contained in:
PJ Reiniger
2022-05-27 16:41:28 -04:00
committed by GitHub
parent db2e1d170e
commit 3e94805220
43 changed files with 429 additions and 813 deletions

View File

@@ -0,0 +1,103 @@
//===- AllocatorBase.h - Simple memory allocation abstraction ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
///
/// This file defines MallocAllocator. MallocAllocator conforms to the LLVM
/// "Allocator" concept which consists of an Allocate method accepting a size
/// and alignment, and a Deallocate accepting a pointer and size. Further, the
/// LLVM "Allocator" concept has overloads of Allocate and Deallocate for
/// setting size and alignment based on the final type. These overloads are
/// typically provided by a base class template \c AllocatorBase.
///
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_ALLOCATORBASE_H
#define WPIUTIL_WPI_ALLOCATORBASE_H
#include "wpi/Compiler.h"
#include "wpi/MemAlloc.h"
namespace wpi {
/// CRTP base class providing obvious overloads for the core \c
/// Allocate() methods of LLVM-style allocators.
///
/// This base class both documents the full public interface exposed by all
/// LLVM-style allocators, and redirects all of the overloads to a single core
/// set of methods which the derived class must define.
template <typename DerivedT> class AllocatorBase {
public:
/// Allocate \a Size bytes of \a Alignment aligned memory. This method
/// must be implemented by \c DerivedT.
void *Allocate(size_t Size, size_t Alignment) {
#ifdef __clang__
static_assert(static_cast<void *(AllocatorBase::*)(size_t, size_t)>(
&AllocatorBase::Allocate) !=
static_cast<void *(DerivedT::*)(size_t, size_t)>(
&DerivedT::Allocate),
"Class derives from AllocatorBase without implementing the "
"core Allocate(size_t, size_t) overload!");
#endif
return static_cast<DerivedT *>(this)->Allocate(Size, Alignment);
}
/// Deallocate \a Ptr to \a Size bytes of memory allocated by this
/// allocator.
void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
#ifdef __clang__
static_assert(
static_cast<void (AllocatorBase::*)(const void *, size_t, size_t)>(
&AllocatorBase::Deallocate) !=
static_cast<void (DerivedT::*)(const void *, size_t, size_t)>(
&DerivedT::Deallocate),
"Class derives from AllocatorBase without implementing the "
"core Deallocate(void *) overload!");
#endif
return static_cast<DerivedT *>(this)->Deallocate(Ptr, Size, Alignment);
}
// The rest of these methods are helpers that redirect to one of the above
// core methods.
/// Allocate space for a sequence of objects without constructing them.
template <typename T> T *Allocate(size_t Num = 1) {
return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
}
/// Deallocate space for a sequence of objects without constructing them.
template <typename T>
std::enable_if_t<!std::is_same<std::remove_cv_t<T>, void>::value, void>
Deallocate(T *Ptr, size_t Num = 1) {
Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T), alignof(T));
}
};
class MallocAllocator : public AllocatorBase<MallocAllocator> {
public:
void Reset() {}
LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, size_t Alignment) {
return allocate_buffer(Size, Alignment);
}
// Pull in base class overloads.
using AllocatorBase<MallocAllocator>::Allocate;
void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
deallocate_buffer(const_cast<void *>(Ptr), Size, Alignment);
}
// Pull in base class overloads.
using AllocatorBase<MallocAllocator>::Deallocate;
void PrintStats() const {}
};
} // namespace wpi
#endif // WPIUTIL_WPI_ALLOCATORBASE_H

View File

@@ -0,0 +1,29 @@
//===-- llvm/Support/DJB.h ---DJB Hash --------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains support for the DJ Bernstein hash function.
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_DJB_H
#define WPIUTIL_WPI_DJB_H
#include <string_view>
namespace wpi {
/// The Bernstein hash function used by the DWARF accelerator tables.
inline uint32_t djbHash(std::string_view Buffer, uint32_t H = 5381) {
for (unsigned char C : Buffer)
H = (H << 5) + H + C;
return H;
}
} // namespace wpi
#endif // WPIUTIL_WPI_DJB_H

View File

@@ -19,7 +19,7 @@
#include "wpi/Compiler.h"
#include "wpi/MathExtras.h"
#include "wpi/MemAlloc.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/ReverseIteration.h"
#include "wpi/type_traits.h"
#include <algorithm>
#include <cassert>
@@ -76,6 +76,8 @@ public:
// empty buckets.
if (empty())
return end();
if (shouldReverseIterate<KeyT>())
return makeIterator(getBucketsEnd() - 1, getBuckets(), *this);
return makeIterator(getBuckets(), getBucketsEnd(), *this);
}
inline iterator end() {
@@ -84,6 +86,8 @@ public:
inline const_iterator begin() const {
if (empty())
return end();
if (shouldReverseIterate<KeyT>())
return makeConstIterator(getBucketsEnd() - 1, getBuckets(), *this);
return makeConstIterator(getBuckets(), getBucketsEnd(), *this);
}
inline const_iterator end() const {
@@ -146,14 +150,18 @@ public:
iterator find(const_arg_type_t<KeyT> Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return makeIterator(TheBucket, getBucketsEnd(),
return makeIterator(TheBucket,
shouldReverseIterate<KeyT>() ? getBuckets()
: getBucketsEnd(),
*this, true);
return end();
}
const_iterator find(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return makeConstIterator(TheBucket, getBucketsEnd(),
return makeConstIterator(TheBucket,
shouldReverseIterate<KeyT>() ? getBuckets()
: getBucketsEnd(),
*this, true);
return end();
}
@@ -167,7 +175,9 @@ public:
iterator find_as(const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return makeIterator(TheBucket, getBucketsEnd(),
return makeIterator(TheBucket,
shouldReverseIterate<KeyT>() ? getBuckets()
: getBucketsEnd(),
*this, true);
return end();
}
@@ -175,7 +185,9 @@ public:
const_iterator find_as(const LookupKeyT &Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return makeConstIterator(TheBucket, getBucketsEnd(),
return makeConstIterator(TheBucket,
shouldReverseIterate<KeyT>() ? getBuckets()
: getBucketsEnd(),
*this, true);
return end();
}
@@ -210,14 +222,20 @@ public:
std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
return std::make_pair(makeIterator(TheBucket,
shouldReverseIterate<KeyT>()
? getBuckets()
: getBucketsEnd(),
*this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket =
InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
return std::make_pair(makeIterator(TheBucket,
shouldReverseIterate<KeyT>()
? getBuckets()
: getBucketsEnd(),
*this, true),
true);
}
@@ -229,13 +247,19 @@ public:
std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
return std::make_pair(makeIterator(TheBucket,
shouldReverseIterate<KeyT>()
? getBuckets()
: getBucketsEnd(),
*this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
return std::make_pair(makeIterator(TheBucket,
shouldReverseIterate<KeyT>()
? getBuckets()
: getBucketsEnd(),
*this, true),
true);
}
@@ -250,14 +274,20 @@ public:
const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
return std::make_pair(makeIterator(TheBucket,
shouldReverseIterate<KeyT>()
? getBuckets()
: getBucketsEnd(),
*this, true),
false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
std::move(KV.second), Val);
return std::make_pair(makeIterator(TheBucket, getBucketsEnd(),
return std::make_pair(makeIterator(TheBucket,
shouldReverseIterate<KeyT>()
? getBuckets()
: getBucketsEnd(),
*this, true),
true);
}
@@ -434,12 +464,20 @@ private:
iterator makeIterator(BucketT *P, BucketT *E,
DebugEpochBase &Epoch,
bool NoAdvance=false) {
if (shouldReverseIterate<KeyT>()) {
BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
return iterator(B, E, Epoch, NoAdvance);
}
return iterator(P, E, Epoch, NoAdvance);
}
const_iterator makeConstIterator(const BucketT *P, const BucketT *E,
const DebugEpochBase &Epoch,
const bool NoAdvance=false) const {
if (shouldReverseIterate<KeyT>()) {
const BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
return const_iterator(B, E, Epoch, NoAdvance);
}
return const_iterator(P, E, Epoch, NoAdvance);
}
@@ -1176,6 +1214,10 @@ public:
assert(isHandleInSync() && "invalid construction!");
if (NoAdvance) return;
if (shouldReverseIterate<KeyT>()) {
RetreatPastEmptyBuckets();
return;
}
AdvancePastEmptyBuckets();
}
@@ -1190,10 +1232,16 @@ public:
reference operator*() const {
assert(isHandleInSync() && "invalid iterator access!");
assert(Ptr != End && "dereferencing end() iterator");
if (shouldReverseIterate<KeyT>())
return Ptr[-1];
return *Ptr;
}
pointer operator->() const {
assert(isHandleInSync() && "invalid iterator access!");
assert(Ptr != End && "dereferencing end() iterator");
if (shouldReverseIterate<KeyT>())
return &(Ptr[-1]);
return Ptr;
}
@@ -1213,6 +1261,12 @@ public:
inline DenseMapIterator& operator++() { // Preincrement
assert(isHandleInSync() && "invalid iterator access!");
assert(Ptr != End && "incrementing end() iterator");
if (shouldReverseIterate<KeyT>()) {
--Ptr;
RetreatPastEmptyBuckets();
return *this;
}
++Ptr;
AdvancePastEmptyBuckets();
return *this;

View File

@@ -0,0 +1,15 @@
#ifndef WPI_REVERSEITERATION_H
#define WPI_REVERSEITERATION_H
#include "wpi/PointerLikeTypeTraits.h"
namespace wpi {
template<class T = void *>
constexpr bool shouldReverseIterate() {
return false;
}
}
#endif

View File

@@ -14,8 +14,9 @@
#ifndef WPIUTIL_WPI_SMALLPTRSET_H
#define WPIUTIL_WPI_SMALLPTRSET_H
#include "wpi/EpochTracker.h"
#include "wpi/Compiler.h"
#include "wpi/PointerLikeTypeTraits.h"
#include "wpi/ReverseIteration.h"
#include "wpi/type_traits.h"
#include <cassert>
#include <cstddef>
@@ -45,7 +46,7 @@ namespace wpi {
/// (-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 {
class SmallPtrSetImplBase : public DebugEpochBase {
friend class SmallPtrSetIteratorImpl;
protected:
@@ -91,6 +92,7 @@ public:
size_type size() const { return NumNonEmpty - NumTombstones; }
void clear() {
incrementEpoch();
// If the capacity of the array is huge, and the # elements used is small,
// shrink the array.
if (!isSmall()) {
@@ -137,12 +139,14 @@ protected:
if (LastTombstone != nullptr) {
*LastTombstone = Ptr;
--NumTombstones;
incrementEpoch();
return std::make_pair(LastTombstone, true);
}
// Nope, there isn't. If we stay small, just 'pushback' now.
if (NumNonEmpty < CurArraySize) {
SmallArray[NumNonEmpty++] = Ptr;
incrementEpoch();
return std::make_pair(SmallArray + (NumNonEmpty - 1), true);
}
// Otherwise, hit the big set case, which will call grow.
@@ -222,6 +226,10 @@ protected:
public:
explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
: Bucket(BP), End(E) {
if (shouldReverseIterate()) {
RetreatIfNotValid();
return;
}
AdvanceIfNotValid();
}
@@ -255,7 +263,8 @@ protected:
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
template <typename PtrTy>
class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
class SmallPtrSetIterator : public SmallPtrSetIteratorImpl,
DebugEpochBase::HandleBase {
using PtrTraits = PointerLikeTypeTraits<PtrTy>;
public:
@@ -265,17 +274,29 @@ public:
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
: SmallPtrSetIteratorImpl(BP, E) {}
explicit SmallPtrSetIterator(const void *const *BP, const void *const *E,
const DebugEpochBase &Epoch)
: SmallPtrSetIteratorImpl(BP, E), DebugEpochBase::HandleBase(&Epoch) {}
// Most methods are provided by the base class.
const PtrTy operator*() const {
assert(isHandleInSync() && "invalid iterator access!");
if (shouldReverseIterate()) {
assert(Bucket > End);
return PtrTraits::getFromVoidPointer(const_cast<void *>(Bucket[-1]));
}
assert(Bucket < End);
return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket));
}
inline SmallPtrSetIterator& operator++() { // Preincrement
assert(isHandleInSync() && "invalid iterator access!");
if (shouldReverseIterate()) {
--Bucket;
RetreatIfNotValid();
return *this;
}
++Bucket;
AdvanceIfNotValid();
return *this;
@@ -379,6 +400,8 @@ public:
}
iterator begin() const {
if (shouldReverseIterate())
return makeIterator(EndPointer() - 1);
return makeIterator(CurArray);
}
iterator end() const { return makeIterator(EndPointer()); }
@@ -386,7 +409,9 @@ public:
private:
/// Create an iterator that dereferences to same place as the given pointer.
iterator makeIterator(const void *const *P) const {
return iterator(P, EndPointer());
if (shouldReverseIterate())
return iterator(P == EndPointer() ? CurArray : P + 1, CurArray, *this);
return iterator(P, EndPointer(), *this);
}
};

View File

@@ -14,6 +14,7 @@
#define WPIUTIL_WPI_STRINGMAP_H
#include "wpi/StringMapEntry.h"
#include "wpi/AllocatorBase.h"
#include "wpi/MemAlloc.h"
#include "wpi/SmallVector.h"
#include "wpi/iterator.h"
@@ -107,8 +108,10 @@ public:
/// keys that are "strings", which are basically ranges of bytes. This does some
/// funky memory allocation and hashing things to make it extremely efficient,
/// storing the string data *after* the value in the map.
template<typename ValueTy>
template <typename ValueTy, typename AllocatorTy = MallocAllocator>
class StringMap : public StringMapImpl {
AllocatorTy Allocator;
public:
using MapEntryTy = StringMapEntry<ValueTy>;
@@ -117,6 +120,14 @@ public:
explicit StringMap(unsigned InitialSize)
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
explicit StringMap(AllocatorTy A)
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), Allocator(A) {
}
StringMap(unsigned InitialSize, AllocatorTy A)
: StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
Allocator(A) {}
StringMap(std::initializer_list<std::pair<std::string_view, ValueTy>> List)
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
for (const auto &P : List) {
@@ -125,10 +136,11 @@ public:
}
StringMap(StringMap &&RHS)
: StringMapImpl(std::move(RHS)) {}
: StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
StringMap(const StringMap &RHS) :
StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {
StringMap(const StringMap &RHS)
: StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
Allocator(RHS.Allocator) {
if (RHS.empty())
return;
@@ -148,7 +160,7 @@ public:
}
TheTable[I] = MapEntryTy::Create(
static_cast<MapEntryTy *>(Bucket)->getKey(),
static_cast<MapEntryTy *>(Bucket)->getKey(), Allocator,
static_cast<MapEntryTy *>(Bucket)->getValue());
HashTable[I] = RHSHashTable[I];
}
@@ -163,6 +175,7 @@ public:
StringMap &operator=(StringMap RHS) {
StringMapImpl::swap(RHS);
std::swap(Allocator, RHS.Allocator);
return *this;
}
@@ -174,13 +187,16 @@ public:
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
StringMapEntryBase *Bucket = TheTable[I];
if (Bucket && Bucket != getTombstoneVal()) {
static_cast<MapEntryTy *>(Bucket)->Destroy();
static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
}
}
}
free(TheTable);
}
AllocatorTy &getAllocator() { return Allocator; }
const AllocatorTy &getAllocator() const { return Allocator; }
using key_type = const char *;
using mapped_type = ValueTy;
using value_type = StringMapEntry<ValueTy>;
@@ -309,7 +325,7 @@ public:
if (Bucket == getTombstoneVal())
--NumTombstones;
Bucket = MapEntryTy::Create(Key, std::forward<ArgsTy>(Args)...);
Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...);
++NumItems;
assert(NumItems + NumTombstones <= NumBuckets);
@@ -327,7 +343,7 @@ public:
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
StringMapEntryBase *&Bucket = TheTable[I];
if (Bucket && Bucket != getTombstoneVal()) {
static_cast<MapEntryTy *>(Bucket)->Destroy();
static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
}
Bucket = nullptr;
}
@@ -343,7 +359,7 @@ public:
void erase(iterator I) {
MapEntryTy &V = *I;
remove(&V);
V.Destroy();
V.Destroy(Allocator);
}
bool erase(std::string_view Key) {

View File

@@ -37,14 +37,22 @@ protected:
/// Helper to tail-allocate \p Key. It'd be nice to generalize this so it
/// could be reused elsewhere, maybe even taking an wpi::function_ref to
/// type-erase the allocator and put it in a source file.
template <typename AllocatorTy>
static void *allocateWithKey(size_t EntrySize, size_t EntryAlign,
std::string_view Key) {
std::string_view Key, AllocatorTy &Allocator);
};
// Define out-of-line to dissuade inlining.
template <typename AllocatorTy>
void *StringMapEntryBase::allocateWithKey(size_t EntrySize, size_t EntryAlign,
std::string_view Key,
AllocatorTy &Allocator) {
size_t KeyLength = Key.size();
// Allocate a new item with space for the string at the end and a null
// terminator.
size_t AllocSize = EntrySize + KeyLength + 1;
void *Allocation = safe_malloc(AllocSize);
void *Allocation = Allocator.Allocate(AllocSize, EntryAlign);
assert(Allocation && "Unhandled out-of-memory");
// Copy the string information.
@@ -54,7 +62,6 @@ protected:
Buffer[KeyLength] = 0; // Null terminate for convenience of clients.
return Allocation;
}
};
/// StringMapEntryStorage - Holds the value in a StringMapEntry.
///
@@ -114,11 +121,11 @@ public:
/// Create a StringMapEntry for the specified key construct the value using
/// \p InitiVals.
template <typename... InitTy>
static StringMapEntry *Create(std::string_view key,
template <typename AllocatorTy, typename... InitTy>
static StringMapEntry *Create(std::string_view key, AllocatorTy &allocator,
InitTy &&... initVals) {
return new (StringMapEntryBase::allocateWithKey(
sizeof(StringMapEntry), alignof(StringMapEntry), key))
sizeof(StringMapEntry), alignof(StringMapEntry), key, allocator))
StringMapEntry(key.size(), std::forward<InitTy>(initVals)...);
}
@@ -131,10 +138,12 @@ public:
/// Destroy - Destroy this StringMapEntry, releasing memory back to the
/// specified allocator.
void Destroy() {
template <typename AllocatorTy> void Destroy(AllocatorTy &allocator) {
// Free memory referenced by the item.
size_t AllocSize = sizeof(StringMapEntry) + this->getKeyLength() + 1;
this->~StringMapEntry();
std::free(static_cast<void *>(this));
allocator.Deallocate(static_cast<void *>(this), AllocSize,
alignof(StringMapEntry));
}
};