138fd1498Szrj// <experimental/memory_resource> -*- C++ -*- 238fd1498Szrj 338fd1498Szrj// Copyright (C) 2015-2018 Free Software Foundation, Inc. 438fd1498Szrj// 538fd1498Szrj// This file is part of the GNU ISO C++ Library. This library is free 638fd1498Szrj// software; you can redistribute it and/or modify it under the 738fd1498Szrj// terms of the GNU General Public License as published by the 838fd1498Szrj// Free Software Foundation; either version 3, or (at your option) 938fd1498Szrj// any later version. 1038fd1498Szrj 1138fd1498Szrj// This library is distributed in the hope that it will be useful, 1238fd1498Szrj// but WITHOUT ANY WARRANTY; without even the implied warranty of 1338fd1498Szrj// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1438fd1498Szrj// GNU General Public License for more details. 1538fd1498Szrj 1638fd1498Szrj// Under Section 7 of GPL version 3, you are granted additional 1738fd1498Szrj// permissions described in the GCC Runtime Library Exception, version 1838fd1498Szrj// 3.1, as published by the Free Software Foundation. 1938fd1498Szrj 2038fd1498Szrj// You should have received a copy of the GNU General Public License and 2138fd1498Szrj// a copy of the GCC Runtime Library Exception along with this program; 2238fd1498Szrj// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 2338fd1498Szrj// <http://www.gnu.org/licenses/>. 2438fd1498Szrj 2538fd1498Szrj/** @file experimental/memory_resource 2638fd1498Szrj * This is a TS C++ Library header. 2738fd1498Szrj */ 2838fd1498Szrj 2938fd1498Szrj#ifndef _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE 3038fd1498Szrj#define _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE 1 3138fd1498Szrj 3238fd1498Szrj#include <memory> 3338fd1498Szrj#include <new> 3438fd1498Szrj#include <atomic> 3538fd1498Szrj#include <cstddef> 3638fd1498Szrj#include <experimental/bits/lfts_config.h> 3738fd1498Szrj 3838fd1498Szrjnamespace std { 3938fd1498Szrj_GLIBCXX_BEGIN_NAMESPACE_VERSION 4038fd1498Szrj 4138fd1498Szrjnamespace experimental { 4238fd1498Szrjinline namespace fundamentals_v2 { 4338fd1498Szrjnamespace pmr { 4438fd1498Szrj#define __cpp_lib_experimental_memory_resources 201402L 4538fd1498Szrj 4638fd1498Szrj class memory_resource; 4738fd1498Szrj 4838fd1498Szrj template <typename _Tp> 4938fd1498Szrj class polymorphic_allocator; 5038fd1498Szrj 5138fd1498Szrj template <typename _Alloc> 5238fd1498Szrj class __resource_adaptor_imp; 5338fd1498Szrj 5438fd1498Szrj template <typename _Alloc> 5538fd1498Szrj using resource_adaptor = __resource_adaptor_imp< 5638fd1498Szrj typename allocator_traits<_Alloc>::template rebind_alloc<char>>; 5738fd1498Szrj 5838fd1498Szrj template <typename _Tp> 5938fd1498Szrj struct __uses_allocator_construction_helper; 6038fd1498Szrj 6138fd1498Szrj // Global memory resources 6238fd1498Szrj memory_resource* new_delete_resource() noexcept; 6338fd1498Szrj memory_resource* null_memory_resource() noexcept; 6438fd1498Szrj 6538fd1498Szrj // The default memory resource 6638fd1498Szrj memory_resource* get_default_resource() noexcept; 6738fd1498Szrj memory_resource* set_default_resource(memory_resource* __r) noexcept; 6838fd1498Szrj 6938fd1498Szrj // Standard memory resources 7038fd1498Szrj 7138fd1498Szrj // 8.5 Class memory_resource 7238fd1498Szrj class memory_resource 7338fd1498Szrj { 7438fd1498Szrj protected: 7538fd1498Szrj static constexpr size_t _S_max_align = alignof(max_align_t); 7638fd1498Szrj 7738fd1498Szrj public: 7838fd1498Szrj virtual ~memory_resource() { } 7938fd1498Szrj 8038fd1498Szrj void* 8138fd1498Szrj allocate(size_t __bytes, size_t __alignment = _S_max_align) 8238fd1498Szrj { return do_allocate(__bytes, __alignment); } 8338fd1498Szrj 8438fd1498Szrj void 8538fd1498Szrj deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align) 8638fd1498Szrj { return do_deallocate(__p, __bytes, __alignment); } 8738fd1498Szrj 8838fd1498Szrj bool 8938fd1498Szrj is_equal(const memory_resource& __other) const noexcept 9038fd1498Szrj { return do_is_equal(__other); } 9138fd1498Szrj 9238fd1498Szrj protected: 9338fd1498Szrj virtual void* 9438fd1498Szrj do_allocate(size_t __bytes, size_t __alignment) = 0; 9538fd1498Szrj 9638fd1498Szrj virtual void 9738fd1498Szrj do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0; 9838fd1498Szrj 9938fd1498Szrj virtual bool 10038fd1498Szrj do_is_equal(const memory_resource& __other) const noexcept = 0; 10138fd1498Szrj }; 10238fd1498Szrj 10338fd1498Szrj inline bool 10438fd1498Szrj operator==(const memory_resource& __a, 10538fd1498Szrj const memory_resource& __b) noexcept 10638fd1498Szrj { return &__a == &__b || __a.is_equal(__b); } 10738fd1498Szrj 10838fd1498Szrj inline bool 10938fd1498Szrj operator!=(const memory_resource& __a, 11038fd1498Szrj const memory_resource& __b) noexcept 11138fd1498Szrj { return !(__a == __b); } 11238fd1498Szrj 11338fd1498Szrj 11438fd1498Szrj // 8.6 Class template polymorphic_allocator 11538fd1498Szrj template <class _Tp> 11638fd1498Szrj class polymorphic_allocator 11738fd1498Szrj { 11838fd1498Szrj using __uses_alloc1_ = __uses_alloc1<memory_resource*>; 11938fd1498Szrj using __uses_alloc2_ = __uses_alloc2<memory_resource*>; 12038fd1498Szrj 12138fd1498Szrj template<typename _Tp1, typename... _Args> 12238fd1498Szrj void 12338fd1498Szrj _M_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args) 12438fd1498Szrj { ::new(__p) _Tp1(std::forward<_Args>(__args)...); } 12538fd1498Szrj 12638fd1498Szrj template<typename _Tp1, typename... _Args> 12738fd1498Szrj void 12838fd1498Szrj _M_construct(__uses_alloc1_, _Tp1* __p, _Args&&... __args) 12938fd1498Szrj { ::new(__p) _Tp1(allocator_arg, this->resource(), 13038fd1498Szrj std::forward<_Args>(__args)...); } 13138fd1498Szrj 13238fd1498Szrj template<typename _Tp1, typename... _Args> 13338fd1498Szrj void 13438fd1498Szrj _M_construct(__uses_alloc2_, _Tp1* __p, _Args&&... __args) 13538fd1498Szrj { ::new(__p) _Tp1(std::forward<_Args>(__args)..., 13638fd1498Szrj this->resource()); } 13738fd1498Szrj 13838fd1498Szrj public: 13938fd1498Szrj using value_type = _Tp; 14038fd1498Szrj 14138fd1498Szrj polymorphic_allocator() noexcept 14238fd1498Szrj : _M_resource(get_default_resource()) 14338fd1498Szrj { } 14438fd1498Szrj 14538fd1498Szrj polymorphic_allocator(memory_resource* __r) 14638fd1498Szrj : _M_resource(__r) 14738fd1498Szrj { _GLIBCXX_DEBUG_ASSERT(__r); } 14838fd1498Szrj 14938fd1498Szrj polymorphic_allocator(const polymorphic_allocator& __other) = default; 15038fd1498Szrj 15138fd1498Szrj template <typename _Up> 15238fd1498Szrj polymorphic_allocator(const polymorphic_allocator<_Up>& 15338fd1498Szrj __other) noexcept 15438fd1498Szrj : _M_resource(__other.resource()) 15538fd1498Szrj { } 15638fd1498Szrj 15738fd1498Szrj polymorphic_allocator& 15838fd1498Szrj operator=(const polymorphic_allocator& __rhs) = default; 15938fd1498Szrj 16038fd1498Szrj _Tp* allocate(size_t __n) 16138fd1498Szrj { return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp), 16238fd1498Szrj alignof(_Tp))); } 16338fd1498Szrj 16438fd1498Szrj void deallocate(_Tp* __p, size_t __n) 16538fd1498Szrj { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } 16638fd1498Szrj 16738fd1498Szrj template <typename _Tp1, typename... _Args> //used here 16838fd1498Szrj void construct(_Tp1* __p, _Args&&... __args) 16938fd1498Szrj { 17038fd1498Szrj memory_resource* const __resource = this->resource(); 17138fd1498Szrj auto __use_tag 17238fd1498Szrj = __use_alloc<_Tp1, memory_resource*, _Args...>(__resource); 17338fd1498Szrj _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); 17438fd1498Szrj } 17538fd1498Szrj 17638fd1498Szrj // Specializations for pair using piecewise construction 17738fd1498Szrj template <typename _Tp1, typename _Tp2, 17838fd1498Szrj typename... _Args1, typename... _Args2> 17938fd1498Szrj void construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t, 18038fd1498Szrj tuple<_Args1...> __x, 18138fd1498Szrj tuple<_Args2...> __y) 18238fd1498Szrj { 18338fd1498Szrj memory_resource* const __resource = this->resource(); 18438fd1498Szrj auto __x_use_tag = 18538fd1498Szrj __use_alloc<_Tp1, memory_resource*, _Args1...>(__resource); 18638fd1498Szrj auto __y_use_tag = 18738fd1498Szrj __use_alloc<_Tp2, memory_resource*, _Args2...>(__resource); 18838fd1498Szrj 18938fd1498Szrj ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct, 19038fd1498Szrj _M_construct_p(__x_use_tag, __x), 19138fd1498Szrj _M_construct_p(__y_use_tag, __y)); 19238fd1498Szrj } 19338fd1498Szrj 19438fd1498Szrj template <typename _Tp1, typename _Tp2> 19538fd1498Szrj void construct(pair<_Tp1,_Tp2>* __p) 19638fd1498Szrj { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); } 19738fd1498Szrj 19838fd1498Szrj template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 19938fd1498Szrj void construct(pair<_Tp1,_Tp2>* __p, _Up&& __x, _Vp&& __y) 20038fd1498Szrj { this->construct(__p, piecewise_construct, 20138fd1498Szrj forward_as_tuple(std::forward<_Up>(__x)), 20238fd1498Szrj forward_as_tuple(std::forward<_Vp>(__y))); } 20338fd1498Szrj 20438fd1498Szrj template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 20538fd1498Szrj void construct(pair<_Tp1,_Tp2>* __p, const std::pair<_Up, _Vp>& __pr) 20638fd1498Szrj { this->construct(__p, piecewise_construct, forward_as_tuple(__pr.first), 20738fd1498Szrj forward_as_tuple(__pr.second)); } 20838fd1498Szrj 20938fd1498Szrj template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 21038fd1498Szrj void construct(pair<_Tp1,_Tp2>* __p, pair<_Up, _Vp>&& __pr) 21138fd1498Szrj { this->construct(__p, piecewise_construct, 21238fd1498Szrj forward_as_tuple(std::forward<_Up>(__pr.first)), 21338fd1498Szrj forward_as_tuple(std::forward<_Vp>(__pr.second))); } 21438fd1498Szrj 21538fd1498Szrj template <typename _Up> 21638fd1498Szrj void destroy(_Up* __p) 21738fd1498Szrj { __p->~_Up(); } 21838fd1498Szrj 21938fd1498Szrj // Return a default-constructed allocator (no allocator propagation) 22038fd1498Szrj polymorphic_allocator select_on_container_copy_construction() const 22138fd1498Szrj { return polymorphic_allocator(); } 22238fd1498Szrj 22338fd1498Szrj memory_resource* resource() const 22438fd1498Szrj { return _M_resource; } 22538fd1498Szrj 22638fd1498Szrj private: 22738fd1498Szrj template<typename _Tuple> 22838fd1498Szrj _Tuple&& 22938fd1498Szrj _M_construct_p(__uses_alloc0, _Tuple& __t) 23038fd1498Szrj { return std::move(__t); } 23138fd1498Szrj 23238fd1498Szrj template<typename... _Args> 23338fd1498Szrj decltype(auto) 23438fd1498Szrj _M_construct_p(__uses_alloc1_ __ua, tuple<_Args...>& __t) 23538fd1498Szrj { return tuple_cat(make_tuple(allocator_arg, *(__ua._M_a)), 23638fd1498Szrj std::move(__t)); } 23738fd1498Szrj 23838fd1498Szrj template<typename... _Args> 23938fd1498Szrj decltype(auto) 24038fd1498Szrj _M_construct_p(__uses_alloc2_ __ua, tuple<_Args...>& __t) 24138fd1498Szrj { return tuple_cat(std::move(__t), make_tuple(*(__ua._M_a))); } 24238fd1498Szrj 24338fd1498Szrj memory_resource* _M_resource; 24438fd1498Szrj }; 24538fd1498Szrj 24638fd1498Szrj template <class _Tp1, class _Tp2> 24738fd1498Szrj bool operator==(const polymorphic_allocator<_Tp1>& __a, 24838fd1498Szrj const polymorphic_allocator<_Tp2>& __b) noexcept 24938fd1498Szrj { return *__a.resource() == *__b.resource(); } 25038fd1498Szrj 25138fd1498Szrj template <class _Tp1, class _Tp2> 25238fd1498Szrj bool operator!=(const polymorphic_allocator<_Tp1>& __a, 25338fd1498Szrj const polymorphic_allocator<_Tp2>& __b) noexcept 25438fd1498Szrj { return !(__a == __b); } 25538fd1498Szrj 25638fd1498Szrj // 8.7.1 __resource_adaptor_imp 25738fd1498Szrj template <typename _Alloc> 25838fd1498Szrj class __resource_adaptor_imp : public memory_resource 25938fd1498Szrj { 260*58e805e6Szrj static_assert(is_same<char, 261*58e805e6Szrj typename allocator_traits<_Alloc>::value_type>::value, 262*58e805e6Szrj "Allocator's value_type is char"); 263*58e805e6Szrj static_assert(is_same<char*, 264*58e805e6Szrj typename allocator_traits<_Alloc>::pointer>::value, 265*58e805e6Szrj "Allocator's pointer type is value_type*"); 266*58e805e6Szrj static_assert(is_same<const char*, 267*58e805e6Szrj typename allocator_traits<_Alloc>::const_pointer>::value, 268*58e805e6Szrj "Allocator's const_pointer type is value_type const*"); 269*58e805e6Szrj static_assert(is_same<void*, 270*58e805e6Szrj typename allocator_traits<_Alloc>::void_pointer>::value, 271*58e805e6Szrj "Allocator's void_pointer type is void*"); 272*58e805e6Szrj static_assert(is_same<const void*, 273*58e805e6Szrj typename allocator_traits<_Alloc>::const_void_pointer>::value, 274*58e805e6Szrj "Allocator's const_void_pointer type is void const*"); 275*58e805e6Szrj 27638fd1498Szrj public: 27738fd1498Szrj using allocator_type = _Alloc; 27838fd1498Szrj 27938fd1498Szrj __resource_adaptor_imp() = default; 28038fd1498Szrj __resource_adaptor_imp(const __resource_adaptor_imp&) = default; 28138fd1498Szrj __resource_adaptor_imp(__resource_adaptor_imp&&) = default; 28238fd1498Szrj 28338fd1498Szrj explicit __resource_adaptor_imp(const _Alloc& __a2) 28438fd1498Szrj : _M_alloc(__a2) 28538fd1498Szrj { } 28638fd1498Szrj 28738fd1498Szrj explicit __resource_adaptor_imp(_Alloc&& __a2) 28838fd1498Szrj : _M_alloc(std::move(__a2)) 28938fd1498Szrj { } 29038fd1498Szrj 29138fd1498Szrj __resource_adaptor_imp& 29238fd1498Szrj operator=(const __resource_adaptor_imp&) = default; 29338fd1498Szrj 294*58e805e6Szrj allocator_type get_allocator() const noexcept { return _M_alloc; } 29538fd1498Szrj 29638fd1498Szrj protected: 29738fd1498Szrj virtual void* 29838fd1498Szrj do_allocate(size_t __bytes, size_t __alignment) 29938fd1498Szrj { 30038fd1498Szrj using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>; 30138fd1498Szrj size_t __new_size = _S_aligned_size(__bytes, 30238fd1498Szrj _S_supported(__alignment) ? 30338fd1498Szrj __alignment : _S_max_align); 30438fd1498Szrj return _Aligned_alloc(_M_alloc).allocate(__new_size); 30538fd1498Szrj } 30638fd1498Szrj 30738fd1498Szrj virtual void 30838fd1498Szrj do_deallocate(void* __p, size_t __bytes, size_t __alignment) 30938fd1498Szrj { 31038fd1498Szrj using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>; 31138fd1498Szrj size_t __new_size = _S_aligned_size(__bytes, 31238fd1498Szrj _S_supported(__alignment) ? 31338fd1498Szrj __alignment : _S_max_align); 31438fd1498Szrj using _Ptr = typename allocator_traits<_Aligned_alloc>::pointer; 31538fd1498Szrj _Aligned_alloc(_M_alloc).deallocate(static_cast<_Ptr>(__p), 31638fd1498Szrj __new_size); 31738fd1498Szrj } 31838fd1498Szrj 31938fd1498Szrj virtual bool 32038fd1498Szrj do_is_equal(const memory_resource& __other) const noexcept 32138fd1498Szrj { 32238fd1498Szrj auto __p = dynamic_cast<const __resource_adaptor_imp*>(&__other); 32338fd1498Szrj return __p ? (_M_alloc == __p->_M_alloc) : false; 32438fd1498Szrj } 32538fd1498Szrj 32638fd1498Szrj private: 32738fd1498Szrj // Calculate Aligned Size 32838fd1498Szrj // Returns a size that is larger than or equal to __size and divisible 329*58e805e6Szrj // by __alignment, where __alignment is required to be a power of 2. 33038fd1498Szrj static size_t 33138fd1498Szrj _S_aligned_size(size_t __size, size_t __alignment) 33238fd1498Szrj { return ((__size - 1)|(__alignment - 1)) + 1; } 33338fd1498Szrj 33438fd1498Szrj // Determine whether alignment meets one of those preconditions: 335*58e805e6Szrj // 1. Equal to Zero 33638fd1498Szrj // 2. Is power of two 33738fd1498Szrj static bool 33838fd1498Szrj _S_supported (size_t __x) 33938fd1498Szrj { return ((__x != 0) && !(__x & (__x - 1))); } 34038fd1498Szrj 34138fd1498Szrj _Alloc _M_alloc; 34238fd1498Szrj }; 34338fd1498Szrj 34438fd1498Szrj // Global memory resources 34538fd1498Szrj 34638fd1498Szrj inline memory_resource* 34738fd1498Szrj new_delete_resource() noexcept 34838fd1498Szrj { 349*58e805e6Szrj using type = resource_adaptor<std::allocator<char>>; 350*58e805e6Szrj alignas(type) static unsigned char __buf[sizeof(type)]; 351*58e805e6Szrj static type* __r = new(__buf) type; 352*58e805e6Szrj return __r; 35338fd1498Szrj } 35438fd1498Szrj 35538fd1498Szrj inline memory_resource* 35638fd1498Szrj null_memory_resource() noexcept 35738fd1498Szrj { 358*58e805e6Szrj class type final : public memory_resource 359*58e805e6Szrj { 360*58e805e6Szrj void* 361*58e805e6Szrj do_allocate(size_t, size_t) override 362*58e805e6Szrj { std::__throw_bad_alloc(); } 363*58e805e6Szrj 364*58e805e6Szrj void 365*58e805e6Szrj do_deallocate(void*, size_t, size_t) noexcept override 366*58e805e6Szrj { } 367*58e805e6Szrj 368*58e805e6Szrj bool 369*58e805e6Szrj do_is_equal(const memory_resource& __other) const noexcept override 370*58e805e6Szrj { return this == &__other; } 371*58e805e6Szrj }; 372*58e805e6Szrj 373*58e805e6Szrj alignas(type) static unsigned char __buf[sizeof(type)]; 374*58e805e6Szrj static type* __r = new(__buf) type; 375*58e805e6Szrj return __r; 37638fd1498Szrj } 37738fd1498Szrj 37838fd1498Szrj // The default memory resource 379*58e805e6Szrj 380*58e805e6Szrj inline std::atomic<memory_resource*>& 381*58e805e6Szrj __get_default_resource() 382*58e805e6Szrj { 383*58e805e6Szrj using type = atomic<memory_resource*>; 384*58e805e6Szrj alignas(type) static unsigned char __buf[sizeof(type)]; 385*58e805e6Szrj static type* __r = new(__buf) type(new_delete_resource()); 386*58e805e6Szrj return *__r; 387*58e805e6Szrj } 388*58e805e6Szrj 38938fd1498Szrj inline memory_resource* 39038fd1498Szrj get_default_resource() noexcept 39138fd1498Szrj { return __get_default_resource().load(); } 39238fd1498Szrj 39338fd1498Szrj inline memory_resource* 39438fd1498Szrj set_default_resource(memory_resource* __r) noexcept 39538fd1498Szrj { 39638fd1498Szrj if (__r == nullptr) 39738fd1498Szrj __r = new_delete_resource(); 39838fd1498Szrj return __get_default_resource().exchange(__r); 39938fd1498Szrj } 40038fd1498Szrj} // namespace pmr 40138fd1498Szrj} // namespace fundamentals_v2 40238fd1498Szrj} // namespace experimental 40338fd1498Szrj 40438fd1498Szrj_GLIBCXX_END_NAMESPACE_VERSION 40538fd1498Szrj} // namespace std 40638fd1498Szrj 40738fd1498Szrj#endif 408