diff --git a/llvm/include/llvm/Support/Allocator.h b/llvm/include/llvm/Support/Allocator.h --- a/llvm/include/llvm/Support/Allocator.h +++ b/llvm/include/llvm/Support/Allocator.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -432,6 +433,44 @@ T *Allocate(size_t num = 1) { return Allocator.Allocate(num); } }; +// This class inherits from the C++17 polymorphic memory resource abstract base +// class to adapt LLVM allocators for use with C++ standard libraries that have +// pmr support (e.g. std::pmr::vector<>, std::pmr::list<>, ...). This allows +// containers with different PMR allocators to interact, at the cost of a +// virtual function call. +template +class AllocMemoryResource : public std::pmr::memory_resource { +public: + AllocMemoryResource(TAlloc *alloc) noexcept : Alloc(alloc) {} + +protected: + void *do_allocate(size_t Bytes, size_t AlignTo) override { + return Alloc->Allocate(Bytes, AlignTo); + }; + void do_deallocate(void *p, size_t Bytes, size_t AlignTo) override { + Alloc->Deallocate(p, Bytes, AlignTo); + }; + bool + do_is_equal(const std::pmr::memory_resource &other) const noexcept override { + return (static_cast(this) == &other); + } + +private: + TAlloc *Alloc; +}; + +// This class inherits from a template allocator class, as well as the +// AllocMemoryResource class, allowing LLVM allocators to opt-in to supporting +// both the LLVM Allocator (Allocate()/Deallocate()) interface as well as the +// C++17 polymorphic memory resource interface. +template +class AllocatorWithMemoryResource : public TAlloc, + public AllocMemoryResource { +public: + AllocatorWithMemoryResource() + : AllocMemoryResource(static_cast(this)) {} +}; + } // end namespace llvm template +#include using namespace llvm; @@ -258,4 +259,24 @@ EXPECT_GT(MockSlabAllocator::GetLastSlabSize(), 4096u); } +// Test an adaptor to allow using LLVM allocators with C++ standard library +// containers. +TEST(AllocatorTest, MemoryResource) { + // Declare a BumpPtrAllocator instance with an associated PMR memory resource. + // (This is similar to using a C++17 monotonic_buffer_resource, but instead + // uses the LLVM BumpPtrAllocator.) + using Allocator = AllocatorWithMemoryResource; + Allocator Alloc; + std::pmr::vector vec(&Alloc); + // Populate the vector with increasing values + vec.resize(64); + std::iota(vec.begin(), vec.end(), 0); + for (size_t i = 0; i < vec.size(); ++i) { + // Verify the vector values + EXPECT_EQ(vec.at(i), i); + // Verify that the vector elements are part of the provide allocator + EXPECT_TRUE(Alloc.identifyObject(&(vec[i])).has_value()); + } +} + } // anonymous namespace