From 2904e861580999aaba678a00993696c44e15a0b9 Mon Sep 17 00:00:00 2001 From: Teon Banek Date: Thu, 25 Apr 2019 15:43:09 +0200 Subject: [PATCH] Add MemoryResource and Allocator interfaces Reviewers: mtomic, mferencevic Reviewed By: mferencevic Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1990 --- src/utils/memory.hpp | 126 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/utils/memory.hpp diff --git a/src/utils/memory.hpp b/src/utils/memory.hpp new file mode 100644 index 000000000..840b089a4 --- /dev/null +++ b/src/utils/memory.hpp @@ -0,0 +1,126 @@ +/// @file +/// This file contains interface and implementation of various MemoryResource +/// and Allocator schemes. It is based on the C++17 features. + +#pragma once + +#include +// Although is in C++17, gcc libstdc++ still need to +// implement it fully. It should be available in the next major release +// version, i.e. gcc 9.x. +#include + +namespace utils { + +/// Abstract class for writing custom memory management, i.e. allocators. +class MemoryResource { + public: + virtual ~MemoryResource() {} + + void *Allocate(size_t bytes, size_t alignment = alignof(std::max_align_t)) { + return DoAllocate(bytes, alignment); + } + + void Deallocate(void *p, size_t bytes, + size_t alignment = alignof(std::max_align_t)) { + return DoDeallocate(p, bytes, alignment); + } + + bool IsEqual(const MemoryResource &other) const noexcept { + return DoIsEqual(other); + } + + private: + virtual void *DoAllocate(size_t bytes, size_t alignment) = 0; + virtual void DoDeallocate(void *p, size_t bytes, size_t alignment) = 0; + virtual bool DoIsEqual(const MemoryResource &other) const noexcept = 0; +}; + +inline bool operator==(const MemoryResource &a, + const MemoryResource &b) noexcept { + return &a == &b || a.IsEqual(b); +} + +inline bool operator!=(const MemoryResource &a, + const MemoryResource &b) noexcept { + return !(a == b); +} + +/// Allocator for a concrete type T using the underlying MemoryResource +/// +/// The API of the Allocator is made such that it fits with the C++ STL +/// requirements. It can be freely used in STL containers while relying on our +/// implementations of MemoryResource. +template +class Allocator { + public: + using value_type = T; + + /// Implicit conversion from MemoryResource. + /// This makes working with STL containers much easier. + Allocator(MemoryResource *memory) : memory_(memory) {} + + template + Allocator(const Allocator &other) noexcept + : memory_(other.GetMemoryResource()) {} + + template + Allocator &operator=(const Allocator &) = delete; + + T *allocate(size_t count_elements) { + return static_cast( + memory_->Allocate(count_elements * sizeof(T), alignof(T))); + } + + void deallocate(T *p, size_t count_elements) { + memory_->Deallocate(p, count_elements * sizeof(T), alignof(T)); + } + + MemoryResource *GetMemoryResource() const { return memory_; } + + private: + MemoryResource *memory_; +}; + +template +bool operator==(const Allocator &a, const Allocator &b) { + return *a.GetMemoryResource() == *b.GetMemoryResource(); +} + +template +bool operator!=(const Allocator &a, const Allocator &b) { + return !(a == b); +} + +/// Wraps std::pmr::memory_resource for use with out MemoryResource +class StdMemoryResource final : public MemoryResource { + public: + /// Implicitly convert std::pmr::memory_resource to StdMemoryResource + StdMemoryResource(std::experimental::pmr::memory_resource *memory) + : memory_(memory) {} + + private: + void *DoAllocate(size_t bytes, size_t alignment) override { + return memory_->allocate(bytes, alignment); + } + + void DoDeallocate(void *p, size_t bytes, size_t alignment) override { + return memory_->deallocate(p, bytes, alignment); + } + + bool DoIsEqual(const MemoryResource &other) const noexcept override { + const auto *other_std = dynamic_cast(&other); + if (!other_std) return false; + return memory_ == other_std->memory_; + } + + std::experimental::pmr::memory_resource *memory_; +}; + +inline MemoryResource *NewDeleteResource() noexcept { + static StdMemoryResource memory( + std::experimental::pmr::new_delete_resource()); + return &memory; +} + +} // namespace utils