mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-27 02:01:42 +00:00
[wpiutil] Reduce llvm collections patches (#4268)
This commit is contained in:
103
wpiutil/src/main/native/include/wpi/AllocatorBase.h
Normal file
103
wpiutil/src/main/native/include/wpi/AllocatorBase.h
Normal 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
|
||||
29
wpiutil/src/main/native/include/wpi/DJB.h
Normal file
29
wpiutil/src/main/native/include/wpi/DJB.h
Normal 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
|
||||
@@ -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;
|
||||
|
||||
15
wpiutil/src/main/native/include/wpi/ReverseIteration.h
Normal file
15
wpiutil/src/main/native/include/wpi/ReverseIteration.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user