1
0
forked from boostorg/core

Compare commits

...

4 Commits

Author SHA1 Message Date
Peter Dimov
90231ed7e0 Document boost::core::memory_resource 2023-01-27 02:42:10 +02:00
Peter Dimov
1aa287e413 Avoid the inclusion of <new> 2023-01-26 19:37:46 +02:00
Peter Dimov
8c65a5b0e8 Work around g++ 4.6 failure 2023-01-26 19:18:44 +02:00
Peter Dimov
99515c341e Add boost::core::memory_resource 2023-01-26 18:09:35 +02:00
7 changed files with 398 additions and 5 deletions

View File

@@ -16,10 +16,12 @@
or C++ standard library type traits instead.
* Marked `boost::ref` member functions and associated methods with `noexcept`.
* Marked `boost::swap` function with `noexcept`, depending on whether the type supports a non-throwing swap operation.
* Added `boost::core::launder`, a portable implementation of `std::launder`.
* Added `BOOST_CORE_ALIGNOF`, a portable implementation of `alignof`.
* Added `boost::core::max_align_t`, a portable equivalent of `std::max_align_t`, and `boost::core::max_align`, the
alignment of `max_align_t`.
* Added [link core.launder `boost::core::launder`], a portable implementation of `std::launder`.
* Added [link core.alignof `BOOST_CORE_ALIGNOF`], a portable implementation of `alignof`.
* Added [link core.max_align `boost::core::max_align_t`], a portable equivalent of `std::max_align_t`, and
`boost::core::max_align`, the alignment of `max_align_t`.
* Added [link core.memory_resource `boost::core::memory_resource`], a portable equivalent of `std::pmr::memory_resource`
from C++17.
[endsect]

View File

@@ -59,6 +59,7 @@ criteria for inclusion is that the utility component be:
[include launder.qbk]
[include lightweight_test.qbk]
[include max_align.qbk]
[include memory_resource.qbk]
[include no_exceptions_support.qbk]
[include noinit_adaptor.qbk]
[include noncopyable.qbk]

View File

@@ -29,7 +29,7 @@ namespace core
union max_align_t;
constexpr max_align = alignof(max_align_t);
constexpr std::size_t max_align = alignof(max_align_t);
} // namespace core
} // namespace boost

139
doc/memory_resource.qbk Normal file
View File

@@ -0,0 +1,139 @@
[/
Copyright 2023 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://boost.org/LICENSE_1_0.txt
]
[section:memory_resource memory_resource]
[simplesect Authors]
* Peter Dimov
[endsimplesect]
[section Header <boost/core/memory_resource.hpp>]
The header `<boost/core/memory_resource.hpp>` defines the class
`boost::core::memory_resource`, a portable equivalent of
`std::pmr::memory_resource` from C++17.
This is not a complete implementation of the standard `<memory_resource>`
header; for such, one should use Boost.Container. The abstract base class
is only provided by Core so that Boost libraries that provide and take
advantage of PMR facilities such as concrete implementations of memory
resources, or implementations of `polymorphic_allocator`, can interoperate.
[section Synopsis]
``
namespace boost
{
namespace core
{
class memory_resource
{
public:
virtual ~memory_resource() = default;
[[nodiscard]] void* allocate( std::size_t bytes, std::size_t alignment = max_align );
void deallocate( void* p, std::size_t bytes, std::size_t alignment = max_align );
bool is_equal( memory_resource const & other ) const noexcept;
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 noexcept = 0;
};
inline bool operator==( memory_resource const& a, memory_resource const& b ) noexcept;
inline bool operator!=( memory_resource const& a, memory_resource const& b ) noexcept;
} // namespace core
} // namespace boost
``
[endsect]
[section `allocate`]
`[[nodiscard]] void* allocate( std::size_t bytes, std::size_t alignment = max_align );`
* *Returns:* `do_allocate( bytes, alignment )`.
* *Remarks:* Implicitly creates objects in the returned region of storage.
[endsect]
[section `deallocate`]
`void deallocate( void* p, std::size_t bytes, std::size_t alignment = max_align );`
* *Effects:* `do_deallocate( bytes, alignment )`.
[endsect]
[section `is_equal`]
`bool is_equal( memory_resource const& other ) const noexcept;`
* *Returns:* `do_is_equal( other )`.
[endsect]
[section `do_allocate`]
`void* do_allocate( std::size_t bytes, std::size_t alignment ) = 0;`
* *Remarks:* A derived class should implement this member function to return
a pointer to allocated storage of size at least `bytes` and alignment at
least `alignment`.
* *Throws:* An appropriate exception (by convention `std::bad_alloc` or
derived) when storage with the specified size and alignment could not be
obtained.
[endsect]
[section `do_deallocate`]
`void do_deallocate( void* p, std::size_t bytes, std::size_t alignment ) = 0;`
* *Remarks:* A derived class should implement this member function to deallocate
a region of storage previously allocated by `do_allocate`.
* *Throws:* Nothing.
[endsect]
[section `do_is_equal`]
`bool do_is_equal( memory_resource const& other ) const noexcept = 0;`
* *Remarks:* A derived class shall implement this function to return `true` if
memory allocated from `*this` can be deallocated from `other` and vice-versa,
otherwise `false`.
[endsect]
[section `operator==`]
`bool operator==( memory_resource const& a, memory_resource const& b ) noexcept;`
* *Returns:* `&a == &b || a.is_equal( b )`.
[endsect]
[section `operator!=`]
`bool operator!=( memory_resource const& a, memory_resource const& b ) noexcept;`
* *Returns:* `!( a == b )`.
[endsect]
[endsect]
[endsect]

View File

@@ -0,0 +1,108 @@
#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 <boost/core/max_align.hpp>
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <cstddef>
// Define our own placement new to avoid the inclusion of <new>
// (~9K extra lines) at Ion Gaztanhaga's request.
//
// We can use our own because [intro.object] p13 says:
//
// Any implicit or explicit invocation of a function named `operator new`
// or `operator new[]` implicitly creates objects in the returned region of
// storage and returns a pointer to a suitable created object.
namespace boost
{
namespace core
{
namespace detail
{
struct placement_new_tag {};
} // namespace detail
} // namespace core
} // namespace boost
inline void* operator new( std::size_t, void* p, boost::core::detail::placement_new_tag )
{
return p;
}
inline void operator delete( void*, void*, boost::core::detail::placement_new_tag )
{
}
namespace boost
{
namespace core
{
class memory_resource
{
public:
#if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || BOOST_WORKAROUND(BOOST_GCC, < 40700)
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 ), core::detail::placement_new_tag() );
}
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

View File

@@ -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 ;

View File

@@ -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 <boost/core/memory_resource.hpp>
#include <boost/core/lightweight_test.hpp>
#include <new>
#include <cstddef>
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();
}