From 99515c341e596d8adf10e81fc93334e4658ece80 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 26 Jan 2023 18:09:35 +0200 Subject: [PATCH] Add boost::core::memory_resource --- include/boost/core/memory_resource.hpp | 76 +++++++++++++ test/Jamfile.v2 | 2 + test/memory_resource_test.cpp | 141 +++++++++++++++++++++++++ 3 files changed, 219 insertions(+) create mode 100644 include/boost/core/memory_resource.hpp create mode 100644 test/memory_resource_test.cpp diff --git a/include/boost/core/memory_resource.hpp b/include/boost/core/memory_resource.hpp new file mode 100644 index 0000000..38a40f6 --- /dev/null +++ b/include/boost/core/memory_resource.hpp @@ -0,0 +1,76 @@ +#ifndef BOOST_CORE_MEMORY_RESOURCE_HPP_INCLUDED +#define BOOST_CORE_MEMORY_RESOURCE_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// Copyright 2023 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +namespace boost +{ +namespace core +{ + +class memory_resource +{ +public: + +#if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) + + virtual ~memory_resource() {} + +#else + + virtual ~memory_resource() = default; + +#endif + + BOOST_ATTRIBUTE_NODISCARD void* allocate( std::size_t bytes, std::size_t alignment = max_align ) + { + // https://github.com/boostorg/container/issues/199 + // https://cplusplus.github.io/LWG/issue3471 + return ::operator new( bytes, do_allocate( bytes, alignment ) ); + } + + void deallocate( void* p, std::size_t bytes, std::size_t alignment = max_align ) + { + do_deallocate( p, bytes, alignment ); + } + + bool is_equal( memory_resource const & other ) const BOOST_NOEXCEPT + { + return do_is_equal( other ); + } + +private: + + virtual void* do_allocate( std::size_t bytes, std::size_t alignment ) = 0; + virtual void do_deallocate( void* p, std::size_t bytes, std::size_t alignment ) = 0; + + virtual bool do_is_equal( memory_resource const & other ) const BOOST_NOEXCEPT = 0; +}; + +inline bool operator==( memory_resource const& a, memory_resource const& b ) BOOST_NOEXCEPT +{ + return &a == &b || a.is_equal( b ); +} + +inline bool operator!=( memory_resource const& a, memory_resource const& b ) BOOST_NOEXCEPT +{ + return !( a == b ); +} + +} // namespace core +} // namespace boost + +#endif // #ifndef BOOST_CORE_MEMORY_RESOURCE_HPP_INCLUDED diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index b27fa97..eeae530 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -357,5 +357,7 @@ run launder_test.cpp ; run alignof_test.cpp ; run max_align_test.cpp ; +run memory_resource_test.cpp ; + use-project /boost/core/swap : ./swap ; build-project ./swap ; diff --git a/test/memory_resource_test.cpp b/test/memory_resource_test.cpp new file mode 100644 index 0000000..a95d558 --- /dev/null +++ b/test/memory_resource_test.cpp @@ -0,0 +1,141 @@ +// Copyright 2023 Peter Dimov +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +static bool do_allocate_called; +static std::size_t do_allocate_bytes; +static std::size_t do_allocate_alignment; + +static bool do_deallocate_called; +static void* do_deallocate_p; +static std::size_t do_deallocate_bytes; +static std::size_t do_deallocate_alignment; + +struct R1: public boost::core::memory_resource +{ + void* do_allocate( std::size_t bytes, std::size_t alignment ) + { + do_allocate_called = true; + do_allocate_bytes = bytes; + do_allocate_alignment = alignment; + + return ::operator new( bytes ); + } + + void do_deallocate( void* p, std::size_t bytes, std::size_t alignment ) + { + do_deallocate_called = true; + do_deallocate_p = p; + do_deallocate_bytes = bytes; + do_deallocate_alignment = alignment; + + ::operator delete( p ); + } + + bool do_is_equal( memory_resource const & /*other*/ ) const BOOST_NOEXCEPT + { + return true; + } +}; + +struct R2: public boost::core::memory_resource +{ + void* do_allocate( std::size_t bytes, std::size_t /*alignment*/ ) + { + return ::operator new( bytes ); + } + + void do_deallocate( void* p, std::size_t /*bytes*/, std::size_t /*alignment*/ ) + { + ::operator delete( p ); + } + + bool do_is_equal( memory_resource const & other ) const BOOST_NOEXCEPT + { + return this == &other; + } +}; + +int main() +{ + { + R1 r1; + + do_allocate_called = false; + do_allocate_bytes = 0; + do_allocate_alignment = 0; + + void* p = r1.allocate( 31 ); + + BOOST_TEST( do_allocate_called ); + BOOST_TEST_EQ( do_allocate_bytes, 31 ); + BOOST_TEST_EQ( do_allocate_alignment, boost::core::max_align ); + + do_deallocate_called = false; + do_deallocate_p = 0; + do_deallocate_bytes = 0; + do_deallocate_alignment = 0; + + r1.deallocate( p, 31 ); + + BOOST_TEST( do_deallocate_called ); + BOOST_TEST_EQ( do_deallocate_p, p ); + BOOST_TEST_EQ( do_deallocate_bytes, 31 ); + BOOST_TEST_EQ( do_deallocate_alignment, boost::core::max_align ); + } + + { + R1 r1; + + do_allocate_called = false; + do_allocate_bytes = 0; + do_allocate_alignment = 0; + + void* p = r1.allocate( 1, 8 ); + + BOOST_TEST( do_allocate_called ); + BOOST_TEST_EQ( do_allocate_bytes, 1 ); + BOOST_TEST_EQ( do_allocate_alignment, 8 ); + + do_deallocate_called = false; + do_deallocate_p = 0; + do_deallocate_bytes = 0; + do_deallocate_alignment = 0; + + r1.deallocate( p, 1, 8 ); + + BOOST_TEST( do_deallocate_called ); + BOOST_TEST_EQ( do_deallocate_p, p ); + BOOST_TEST_EQ( do_deallocate_bytes, 1 ); + BOOST_TEST_EQ( do_deallocate_alignment, 8 ); + } + + { + R1 r1; + R1 r2; + + BOOST_TEST( r1 == r1 ); + BOOST_TEST_NOT( r1 != r1 ); + + BOOST_TEST( r1 == r2 ); + BOOST_TEST_NOT( r1 != r2 ); + } + + { + R2 r1; + R2 r2; + + BOOST_TEST( r1 == r1 ); + BOOST_TEST_NOT( r1 != r1 ); + + BOOST_TEST_NOT( r1 == r2 ); + BOOST_TEST( r1 != r2 ); + } + + return boost::report_errors(); +}