// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "pma/MemoryResource.h" #include "pma/resources/DefaultMemoryResource.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4365 4987) #endif #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning(pop) #pragma warning(disable : 4068) #endif namespace pma { namespace impl { template struct max_align_of { using type = typename std::conditional<(alignof(T) > alignof(U)), T, U>::type; }; template class PolyAllocator { public: using value_type = T; using traits_type = std::allocator_traits; template friend class PolyAllocator; public: PolyAllocator() { #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wexit-time-destructors" #endif static TDefaultMemoryResource dmr; #ifdef __clang__ #pragma clang diagnostic pop #endif pMemRes = &dmr; } PolyAllocator(MemoryResource* memRes) : PolyAllocator{} { if (memRes != nullptr) { pMemRes = memRes; } } PolyAllocator(std::nullptr_t /*unused*/) : PolyAllocator{} { } template PolyAllocator(const PolyAllocator& rhs) : pMemRes{rhs.pMemRes} { } void* allocateBytes(std::size_t size, std::size_t alignment = Alignment) { return pMemRes->allocate(size, alignment); } void deallocateBytes(void* ptr, std::size_t size, std::size_t alignment = Alignment) { pMemRes->deallocate(ptr, size, alignment); } template typename std::enable_if::value, U*>::type allocateObject(std::size_t count, std::size_t alignment = Alignment) { return static_cast(allocateBytes(count * sizeof(U), alignment)); } template typename std::enable_if::value>::type deallocateObject(U* ptr, std::size_t count, std::size_t alignment = Alignment) { deallocateBytes(static_cast(ptr), count * sizeof(U), alignment); } template U* newObject(Args&& ... args) { auto ptr = traits_type::allocate(*this, 1ul); assert(ptr != nullptr); traits_type::construct(*this, ptr, std::forward(args)...); return ptr; } template void deleteObject(U* ptr) { traits_type::destroy(*this, ptr); traits_type::deallocate(*this, ptr, 1ul); } // Allocation function as requested by standard-library containers value_type* allocate(std::size_t count) { return allocateObject(count); } // Deallocation function as requested by standard-library containers void deallocate(value_type* ptr, std::size_t count) { deallocateObject(ptr, count); } static std::size_t getAlignment() { return Alignment; } MemoryResource* getMemoryResource() const { return pMemRes; } private: MemoryResource* pMemRes; }; } // namespace impl template::type), class TDefaultMemoryResource = DefaultMemoryResource> class PolyAllocator : public std::scoped_allocator_adaptor > { private: using Impl = impl::PolyAllocator; using Base = std::scoped_allocator_adaptor; public: template struct rebind { using other = PolyAllocator; }; PolyAllocator() = default; PolyAllocator(MemoryResource* memRes) : Base{Impl{memRes}} { } template PolyAllocator(const PolyAllocator& rhs) : Base{rhs} { } template PolyAllocator(const impl::PolyAllocator& rhs) : Base{rhs} { } }; template bool operator==(const PolyAllocator& lhs, const PolyAllocator& rhs) { return (TAlignment == UAlignment && lhs.getMemoryResource() == rhs.getMemoryResource()); } template bool operator!=(const PolyAllocator& lhs, const PolyAllocator& rhs) { return !(lhs == rhs); } } // namespace pma