to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
427 lines
13 KiB
C++
427 lines
13 KiB
C++
// -*- C++ -*-
|
|
//===------------------------ memory_resource -----------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE
|
|
#define _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE
|
|
|
|
/**
|
|
experimental/memory_resource synopsis
|
|
|
|
// C++1y
|
|
|
|
namespace std {
|
|
namespace experimental {
|
|
inline namespace fundamentals_v1 {
|
|
namespace pmr {
|
|
|
|
class memory_resource;
|
|
|
|
bool operator==(const memory_resource& a,
|
|
const memory_resource& b) noexcept;
|
|
bool operator!=(const memory_resource& a,
|
|
const memory_resource& b) noexcept;
|
|
|
|
template <class Tp> class polymorphic_allocator;
|
|
|
|
template <class T1, class T2>
|
|
bool operator==(const polymorphic_allocator<T1>& a,
|
|
const polymorphic_allocator<T2>& b) noexcept;
|
|
template <class T1, class T2>
|
|
bool operator!=(const polymorphic_allocator<T1>& a,
|
|
const polymorphic_allocator<T2>& b) noexcept;
|
|
|
|
// The name resource_adaptor_imp is for exposition only.
|
|
template <class Allocator> class resource_adaptor_imp;
|
|
|
|
template <class Allocator>
|
|
using resource_adaptor = resource_adaptor_imp<
|
|
allocator_traits<Allocator>::rebind_alloc<char>>;
|
|
|
|
// Global memory resources
|
|
memory_resource* new_delete_resource() noexcept;
|
|
memory_resource* null_memory_resource() noexcept;
|
|
|
|
// The default memory resource
|
|
memory_resource* set_default_resource(memory_resource* r) noexcept;
|
|
memory_resource* get_default_resource() noexcept;
|
|
|
|
// Standard memory resources
|
|
struct pool_options;
|
|
class synchronized_pool_resource;
|
|
class unsynchronized_pool_resource;
|
|
class monotonic_buffer_resource;
|
|
|
|
} // namespace pmr
|
|
} // namespace fundamentals_v1
|
|
} // namespace experimental
|
|
} // namespace std
|
|
|
|
*/
|
|
|
|
#include <experimental/__config>
|
|
#include <experimental/__memory>
|
|
#include <limits>
|
|
#include <memory>
|
|
#include <new>
|
|
#include <stdexcept>
|
|
#include <__tuple>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <cstddef>
|
|
#include <cstdlib>
|
|
#include <__debug>
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
#pragma GCC system_header
|
|
#endif
|
|
|
|
_LIBCPP_PUSH_MACROS
|
|
#include <__undef_macros>
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
|
|
|
|
// Round __s up to next multiple of __a.
|
|
inline _LIBCPP_INLINE_VISIBILITY
|
|
size_t __aligned_allocation_size(size_t __s, size_t __a) _NOEXCEPT
|
|
{
|
|
_LIBCPP_ASSERT(__s + __a > __s, "aligned allocation size overflows");
|
|
return (__s + __a - 1) & ~(__a - 1);
|
|
}
|
|
|
|
// 8.5, memory.resource
|
|
class _LIBCPP_TYPE_VIS memory_resource
|
|
{
|
|
static const size_t __max_align = _LIBCPP_ALIGNOF(max_align_t);
|
|
|
|
// 8.5.2, memory.resource.public
|
|
public:
|
|
virtual ~memory_resource() = default;
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
void* allocate(size_t __bytes, size_t __align = __max_align)
|
|
{ return do_allocate(__bytes, __align); }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
void deallocate(void * __p, size_t __bytes, size_t __align = __max_align)
|
|
{ do_deallocate(__p, __bytes, __align); }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
bool is_equal(memory_resource const & __other) const _NOEXCEPT
|
|
{ return do_is_equal(__other); }
|
|
|
|
// 8.5.3, memory.resource.priv
|
|
protected:
|
|
virtual void* do_allocate(size_t, size_t) = 0;
|
|
virtual void do_deallocate(void*, size_t, size_t) = 0;
|
|
virtual bool do_is_equal(memory_resource const &) const _NOEXCEPT = 0;
|
|
};
|
|
|
|
// 8.5.4, memory.resource.eq
|
|
inline _LIBCPP_INLINE_VISIBILITY
|
|
bool operator==(memory_resource const & __lhs,
|
|
memory_resource const & __rhs) _NOEXCEPT
|
|
{
|
|
return &__lhs == &__rhs || __lhs.is_equal(__rhs);
|
|
}
|
|
|
|
inline _LIBCPP_INLINE_VISIBILITY
|
|
bool operator!=(memory_resource const & __lhs,
|
|
memory_resource const & __rhs) _NOEXCEPT
|
|
{
|
|
return !(__lhs == __rhs);
|
|
}
|
|
|
|
_LIBCPP_FUNC_VIS
|
|
memory_resource * new_delete_resource() _NOEXCEPT;
|
|
|
|
_LIBCPP_FUNC_VIS
|
|
memory_resource * null_memory_resource() _NOEXCEPT;
|
|
|
|
_LIBCPP_FUNC_VIS
|
|
memory_resource * get_default_resource() _NOEXCEPT;
|
|
|
|
_LIBCPP_FUNC_VIS
|
|
memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT;
|
|
|
|
// 8.6, memory.polymorphic.allocator.class
|
|
|
|
// 8.6.1, memory.polymorphic.allocator.overview
|
|
template <class _ValueType>
|
|
class _LIBCPP_TEMPLATE_VIS polymorphic_allocator
|
|
{
|
|
public:
|
|
typedef _ValueType value_type;
|
|
|
|
// 8.6.2, memory.polymorphic.allocator.ctor
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
polymorphic_allocator() _NOEXCEPT
|
|
: __res_(_VSTD_LFTS_PMR::get_default_resource())
|
|
{}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
polymorphic_allocator(memory_resource * __r) _NOEXCEPT
|
|
: __res_(__r)
|
|
{}
|
|
|
|
polymorphic_allocator(polymorphic_allocator const &) = default;
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
polymorphic_allocator(polymorphic_allocator<_Tp> const & __other) _NOEXCEPT
|
|
: __res_(__other.resource())
|
|
{}
|
|
|
|
polymorphic_allocator &
|
|
operator=(polymorphic_allocator const &) = delete;
|
|
|
|
// 8.6.3, memory.polymorphic.allocator.mem
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
_ValueType* allocate(size_t __n) {
|
|
if (__n > __max_size()) {
|
|
__throw_length_error(
|
|
"std::experimental::pmr::polymorphic_allocator<T>::allocate(size_t n)"
|
|
" 'n' exceeds maximum supported size");
|
|
}
|
|
return static_cast<_ValueType*>(
|
|
__res_->allocate(__n * sizeof(_ValueType), _LIBCPP_ALIGNOF(_ValueType))
|
|
);
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
void deallocate(_ValueType * __p, size_t __n) _NOEXCEPT {
|
|
_LIBCPP_ASSERT(__n <= __max_size(),
|
|
"deallocate called for size which exceeds max_size()");
|
|
__res_->deallocate(__p, __n * sizeof(_ValueType), _LIBCPP_ALIGNOF(_ValueType));
|
|
}
|
|
|
|
template <class _Tp, class ..._Ts>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
void construct(_Tp* __p, _Ts &&... __args)
|
|
{
|
|
_VSTD_LFTS::__lfts_user_alloc_construct(
|
|
__p, *this, _VSTD::forward<_Ts>(__args)...
|
|
);
|
|
}
|
|
|
|
template <class _T1, class _T2, class ..._Args1, class ..._Args2>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
void construct(pair<_T1, _T2>* __p, piecewise_construct_t,
|
|
tuple<_Args1...> __x, tuple<_Args2...> __y)
|
|
{
|
|
::new ((void*)__p) pair<_T1, _T2>(piecewise_construct
|
|
, __transform_tuple(
|
|
typename __lfts_uses_alloc_ctor<
|
|
_T1, polymorphic_allocator&, _Args1...
|
|
>::type()
|
|
, _VSTD::move(__x)
|
|
, typename __make_tuple_indices<sizeof...(_Args1)>::type{}
|
|
)
|
|
, __transform_tuple(
|
|
typename __lfts_uses_alloc_ctor<
|
|
_T2, polymorphic_allocator&, _Args2...
|
|
>::type()
|
|
, _VSTD::move(__y)
|
|
, typename __make_tuple_indices<sizeof...(_Args2)>::type{}
|
|
)
|
|
);
|
|
}
|
|
|
|
template <class _T1, class _T2>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
void construct(pair<_T1, _T2>* __p) {
|
|
construct(__p, piecewise_construct, tuple<>(), tuple<>());
|
|
}
|
|
|
|
template <class _T1, class _T2, class _Up, class _Vp>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
void construct(pair<_T1, _T2> * __p, _Up && __u, _Vp && __v) {
|
|
construct(__p, piecewise_construct
|
|
, _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__u))
|
|
, _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__v)));
|
|
}
|
|
|
|
template <class _T1, class _T2, class _U1, class _U2>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> const & __pr) {
|
|
construct(__p, piecewise_construct
|
|
, _VSTD::forward_as_tuple(__pr.first)
|
|
, _VSTD::forward_as_tuple(__pr.second));
|
|
}
|
|
|
|
template <class _T1, class _T2, class _U1, class _U2>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> && __pr){
|
|
construct(__p, piecewise_construct
|
|
, _VSTD::forward_as_tuple(_VSTD::forward<_U1>(__pr.first))
|
|
, _VSTD::forward_as_tuple(_VSTD::forward<_U2>(__pr.second)));
|
|
}
|
|
|
|
template <class _Tp>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
void destroy(_Tp * __p) _NOEXCEPT
|
|
{ __p->~_Tp(); }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
polymorphic_allocator
|
|
select_on_container_copy_construction() const _NOEXCEPT
|
|
{ return polymorphic_allocator(); }
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
memory_resource * resource() const _NOEXCEPT
|
|
{ return __res_; }
|
|
|
|
private:
|
|
template <class ..._Args, size_t ..._Idx>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
tuple<_Args&&...>
|
|
__transform_tuple(integral_constant<int, 0>, tuple<_Args...>&& __t,
|
|
__tuple_indices<_Idx...>) const
|
|
{
|
|
return _VSTD::forward_as_tuple(_VSTD::get<_Idx>(_VSTD::move(__t))...);
|
|
}
|
|
|
|
template <class ..._Args, size_t ..._Idx>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>
|
|
__transform_tuple(integral_constant<int, 1>, tuple<_Args...> && __t,
|
|
__tuple_indices<_Idx...>)
|
|
{
|
|
using _Tup = tuple<allocator_arg_t const&, polymorphic_allocator&, _Args&&...>;
|
|
return _Tup(allocator_arg, *this,
|
|
_VSTD::get<_Idx>(_VSTD::move(__t))...);
|
|
}
|
|
|
|
template <class ..._Args, size_t ..._Idx>
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
tuple<_Args&&..., polymorphic_allocator&>
|
|
__transform_tuple(integral_constant<int, 2>, tuple<_Args...> && __t,
|
|
__tuple_indices<_Idx...>)
|
|
{
|
|
using _Tup = tuple<_Args&&..., polymorphic_allocator&>;
|
|
return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., *this);
|
|
}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
size_t __max_size() const _NOEXCEPT
|
|
{ return numeric_limits<size_t>::max() / sizeof(value_type); }
|
|
|
|
memory_resource * __res_;
|
|
};
|
|
|
|
// 8.6.4, memory.polymorphic.allocator.eq
|
|
|
|
template <class _Tp, class _Up>
|
|
inline _LIBCPP_INLINE_VISIBILITY
|
|
bool operator==(polymorphic_allocator<_Tp> const & __lhs,
|
|
polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT
|
|
{
|
|
return *__lhs.resource() == *__rhs.resource();
|
|
}
|
|
|
|
template <class _Tp, class _Up>
|
|
inline _LIBCPP_INLINE_VISIBILITY
|
|
bool operator!=(polymorphic_allocator<_Tp> const & __lhs,
|
|
polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT
|
|
{
|
|
return !(__lhs == __rhs);
|
|
}
|
|
|
|
// 8.7, memory.resource.adaptor
|
|
|
|
// 8.7.1, memory.resource.adaptor.overview
|
|
template <class _CharAlloc>
|
|
class _LIBCPP_TEMPLATE_VIS __resource_adaptor_imp
|
|
: public memory_resource
|
|
{
|
|
using _CTraits = allocator_traits<_CharAlloc>;
|
|
static_assert(is_same<typename _CTraits::value_type, char>::value
|
|
&& is_same<typename _CTraits::pointer, char*>::value
|
|
&& is_same<typename _CTraits::void_pointer, void*>::value, "");
|
|
|
|
static const size_t _MaxAlign = _LIBCPP_ALIGNOF(max_align_t);
|
|
|
|
using _Alloc = typename _CTraits::template rebind_alloc<
|
|
typename aligned_storage<_MaxAlign, _MaxAlign>::type
|
|
>;
|
|
|
|
using _ValueType = typename _Alloc::value_type;
|
|
|
|
_Alloc __alloc_;
|
|
|
|
public:
|
|
typedef _CharAlloc allocator_type;
|
|
|
|
__resource_adaptor_imp() = default;
|
|
__resource_adaptor_imp(__resource_adaptor_imp const &) = default;
|
|
__resource_adaptor_imp(__resource_adaptor_imp &&) = default;
|
|
|
|
// 8.7.2, memory.resource.adaptor.ctor
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
explicit __resource_adaptor_imp(allocator_type const & __a)
|
|
: __alloc_(__a)
|
|
{}
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
explicit __resource_adaptor_imp(allocator_type && __a)
|
|
: __alloc_(_VSTD::move(__a))
|
|
{}
|
|
|
|
__resource_adaptor_imp &
|
|
operator=(__resource_adaptor_imp const &) = default;
|
|
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
allocator_type get_allocator() const
|
|
{ return __alloc_; }
|
|
|
|
// 8.7.3, memory.resource.adaptor.mem
|
|
protected:
|
|
virtual void * do_allocate(size_t __bytes, size_t)
|
|
{
|
|
if (__bytes > __max_size()) {
|
|
__throw_length_error(
|
|
"std::experimental::pmr::resource_adaptor<T>::do_allocate(size_t bytes, size_t align)"
|
|
" 'bytes' exceeds maximum supported size");
|
|
}
|
|
size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
|
|
return __alloc_.allocate(__s);
|
|
}
|
|
|
|
virtual void do_deallocate(void * __p, size_t __bytes, size_t)
|
|
{
|
|
_LIBCPP_ASSERT(__bytes <= __max_size(),
|
|
"do_deallocate called for size which exceeds the maximum allocation size");
|
|
size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
|
|
__alloc_.deallocate((_ValueType*)__p, __s);
|
|
}
|
|
|
|
virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT {
|
|
__resource_adaptor_imp const * __p
|
|
= dynamic_cast<__resource_adaptor_imp const *>(&__other);
|
|
return __p ? __alloc_ == __p->__alloc_ : false;
|
|
}
|
|
|
|
private:
|
|
_LIBCPP_INLINE_VISIBILITY
|
|
size_t __max_size() const _NOEXCEPT {
|
|
return numeric_limits<size_t>::max() - _MaxAlign;
|
|
}
|
|
};
|
|
|
|
template <class _Alloc>
|
|
using resource_adaptor = __resource_adaptor_imp<
|
|
typename allocator_traits<_Alloc>::template rebind_alloc<char>
|
|
>;
|
|
|
|
_LIBCPP_END_NAMESPACE_LFTS_PMR
|
|
|
|
_LIBCPP_POP_MACROS
|
|
|
|
#endif /* _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE */
|