forked from boostorg/core
Compare commits
4 Commits
feature/ma
...
feature/me
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90231ed7e0 | ||
|
|
1aa287e413 | ||
|
|
8c65a5b0e8 | ||
|
|
99515c341e |
@@ -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]
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
139
doc/memory_resource.qbk
Normal 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]
|
||||
108
include/boost/core/memory_resource.hpp
Normal file
108
include/boost/core/memory_resource.hpp
Normal 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
|
||||
@@ -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 ;
|
||||
|
||||
141
test/memory_resource_test.cpp
Normal file
141
test/memory_resource_test.cpp
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user