// -*- C++ -*- // Copyright (C) 2015-2016 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // . /** @file experimental/memory_resource * This is a TS C++ Library header. */ #ifndef _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE #define _GLIBCXX_EXPERIMENTAL_MEMORY_RESOURCE 1 #include #include #include #include #include #include namespace std { namespace experimental { inline namespace fundamentals_v2 { namespace pmr { _GLIBCXX_BEGIN_NAMESPACE_VERSION #define __cpp_lib_experimental_memory_resources 201402L class memory_resource; template class polymorphic_allocator; template class __resource_adaptor_imp; template using resource_adaptor = __resource_adaptor_imp< typename allocator_traits<_Alloc>::template rebind_alloc>; template struct __uses_allocator_construction_helper; // Global memory resources memory_resource* new_delete_resource() noexcept; memory_resource* null_memory_resource() noexcept; // The default memory resource memory_resource* get_default_resource() noexcept; memory_resource* set_default_resource(memory_resource* __r) noexcept; // Standard memory resources // 8.5 Class memory_resource class memory_resource { protected: static constexpr size_t _S_max_align = alignof(max_align_t); public: virtual ~memory_resource() { } void* allocate(size_t __bytes, size_t __alignment = _S_max_align) { return do_allocate(__bytes, __alignment); } void deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align) { return do_deallocate(__p, __bytes, __alignment); } bool is_equal(const memory_resource& __other) const noexcept { return do_is_equal(__other); } protected: virtual void* do_allocate(size_t __bytes, size_t __alignment) = 0; virtual void do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0; virtual bool do_is_equal(const memory_resource& __other) const noexcept = 0; }; inline bool operator==(const memory_resource& __a, const memory_resource& __b) noexcept { return &__a == &__b || __a.is_equal(__b); } inline bool operator!=(const memory_resource& __a, const memory_resource& __b) noexcept { return !(__a == __b); } // 8.6 Class template polymorphic_allocator template class polymorphic_allocator { using __uses_alloc1_ = __uses_alloc1; using __uses_alloc2_ = __uses_alloc2; template void _M_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args) { ::new(__p) _Tp1(std::forward<_Args>(__args)...); } template void _M_construct(__uses_alloc1_, _Tp1* __p, _Args&&... __args) { ::new(__p) _Tp1(allocator_arg, this->resource(), std::forward<_Args>(__args)...); } template void _M_construct(__uses_alloc2_, _Tp1* __p, _Args&&... __args) { ::new(__p) _Tp1(std::forward<_Args>(__args)..., this->resource()); } public: using value_type = _Tp; polymorphic_allocator() noexcept : _M_resource(get_default_resource()) { } polymorphic_allocator(memory_resource* __r) : _M_resource(__r) { _GLIBCXX_DEBUG_ASSERT(__r); } polymorphic_allocator(const polymorphic_allocator& __other) = default; template polymorphic_allocator(const polymorphic_allocator<_Up>& __other) noexcept : _M_resource(__other.resource()) { } polymorphic_allocator& operator=(const polymorphic_allocator& __rhs) = default; _Tp* allocate(size_t __n) { return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp), alignof(_Tp))); } void deallocate(_Tp* __p, size_t __n) { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } template //used here void construct(_Tp1* __p, _Args&&... __args) { auto __use_tag = __use_alloc<_Tp1, memory_resource*, _Args...>(this->resource()); _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); } // Specializations for pair using piecewise construction template void construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t, tuple<_Args1...> __x, tuple<_Args2...> __y) { auto __x_use_tag = __use_alloc<_Tp1, memory_resource*, _Args1...>(this->resource()); auto __y_use_tag = __use_alloc<_Tp2, memory_resource*, _Args2...>(this->resource()); ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct, _M_construct_p(__x_use_tag, __x), _M_construct_p(__y_use_tag, __y)); } template void construct(pair<_Tp1,_Tp2>* __p) { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); } template void construct(pair<_Tp1,_Tp2>* __p, _Up&& __x, _Vp&& __y) { this->construct(__p, piecewise_construct, forward_as_tuple(std::forward<_Up>(__x)), forward_as_tuple(std::forward<_Vp>(__y))); } template void construct(pair<_Tp1,_Tp2>* __p, const std::pair<_Up, _Vp>& __pr) { this->construct(__p, piecewise_construct, forward_as_tuple(__pr.first), forward_as_tuple(__pr.second)); } template void construct(pair<_Tp1,_Tp2>* __p, pair<_Up, _Vp>&& __pr) { this->construct(__p, piecewise_construct, forward_as_tuple(std::forward<_Up>(__pr.first)), forward_as_tuple(std::forward<_Vp>(__pr.second))); } template void destroy(_Up* __p) { __p->~_Up(); } // Return a default-constructed allocator (no allocator propagation) polymorphic_allocator select_on_container_copy_construction() const { return polymorphic_allocator(); } memory_resource* resource() const { return _M_resource; } private: template _Tuple&& _M_construct_p(__uses_alloc0, _Tuple& __t) { return std::move(__t); } template decltype(auto) _M_construct_p(__uses_alloc1_ __ua, tuple<_Args...>& __t) { return tuple_cat(make_tuple(allocator_arg, *(__ua._M_a)), std::move(__t)); } template decltype(auto) _M_construct_p(__uses_alloc2_ __ua, tuple<_Args...>& __t) { return tuple_cat(std::move(__t), make_tuple(*(__ua._M_a))); } memory_resource* _M_resource; }; template bool operator==(const polymorphic_allocator<_Tp1>& __a, const polymorphic_allocator<_Tp2>& __b) noexcept { return *__a.resource() == *__b.resource(); } template bool operator!=(const polymorphic_allocator<_Tp1>& __a, const polymorphic_allocator<_Tp2>& __b) noexcept { return !(__a == __b); } // 8.7.1 __resource_adaptor_imp template class __resource_adaptor_imp : public memory_resource { public: using allocator_type = _Alloc; __resource_adaptor_imp() = default; __resource_adaptor_imp(const __resource_adaptor_imp&) = default; __resource_adaptor_imp(__resource_adaptor_imp&&) = default; explicit __resource_adaptor_imp(const _Alloc& __a2) : _M_alloc(__a2) { } explicit __resource_adaptor_imp(_Alloc&& __a2) : _M_alloc(std::move(__a2)) { } __resource_adaptor_imp& operator=(const __resource_adaptor_imp&) = default; allocator_type get_allocator() const { return _M_alloc; } protected: virtual void* do_allocate(size_t __bytes, size_t __alignment) { using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>; size_t __new_size = _S_aligned_size(__bytes, _S_supported(__alignment) ? __alignment : _S_max_align); return _Aligned_alloc(_M_alloc).allocate(__new_size); } virtual void do_deallocate(void* __p, size_t __bytes, size_t __alignment) { using _Aligned_alloc = std::__alloc_rebind<_Alloc, char>; size_t __new_size = _S_aligned_size(__bytes, _S_supported(__alignment) ? __alignment : _S_max_align); using _Ptr = typename allocator_traits<_Aligned_alloc>::pointer; _Aligned_alloc(_M_alloc).deallocate(static_cast<_Ptr>(__p), __new_size); } virtual bool do_is_equal(const memory_resource& __other) const noexcept { auto __p = dynamic_cast(&__other); return __p ? (_M_alloc == __p->_M_alloc) : false; } private: // Calculate Aligned Size // Returns a size that is larger than or equal to __size and divisible // by __alignment, where __alignment is required to be the power of 2. static size_t _S_aligned_size(size_t __size, size_t __alignment) { return ((__size - 1)|(__alignment - 1)) + 1; } // Determine whether alignment meets one of those preconditions: // 1. Equals to Zero // 2. Is power of two static bool _S_supported (size_t __x) { return ((__x != 0) && !(__x & (__x - 1))); } _Alloc _M_alloc; }; // Global memory resources inline std::atomic& __get_default_resource() { static atomic _S_default_resource(new_delete_resource()); return _S_default_resource; } inline memory_resource* new_delete_resource() noexcept { static resource_adaptor> __r; return static_cast(&__r); } template class __null_memory_resource : private memory_resource { protected: void* do_allocate(size_t, size_t) { std::__throw_bad_alloc(); } void do_deallocate(void*, size_t, size_t) noexcept { } bool do_is_equal(const memory_resource& __other) const noexcept { return this == &__other; } friend memory_resource* null_memory_resource() noexcept; }; inline memory_resource* null_memory_resource() noexcept { static __null_memory_resource __r; return static_cast(&__r); } // The default memory resource inline memory_resource* get_default_resource() noexcept { return __get_default_resource().load(); } inline memory_resource* set_default_resource(memory_resource* __r) noexcept { if (__r == nullptr) __r = new_delete_resource(); return __get_default_resource().exchange(__r); } _GLIBCXX_END_NAMESPACE_VERSION } // namespace pmr } // namespace fundamentals_v2 } // namespace experimental } // namespace std #endif