1627f7eb2Smrg// <memory_resource> -*- C++ -*- 2627f7eb2Smrg 3*4c3eb207Smrg// Copyright (C) 2018-2020 Free Software Foundation, Inc. 4627f7eb2Smrg// 5627f7eb2Smrg// This file is part of the GNU ISO C++ Library. This library is free 6627f7eb2Smrg// software; you can redistribute it and/or modify it under the 7627f7eb2Smrg// terms of the GNU General Public License as published by the 8627f7eb2Smrg// Free Software Foundation; either version 3, or (at your option) 9627f7eb2Smrg// any later version. 10627f7eb2Smrg 11627f7eb2Smrg// This library is distributed in the hope that it will be useful, 12627f7eb2Smrg// but WITHOUT ANY WARRANTY; without even the implied warranty of 13627f7eb2Smrg// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14627f7eb2Smrg// GNU General Public License for more details. 15627f7eb2Smrg 16627f7eb2Smrg// Under Section 7 of GPL version 3, you are granted additional 17627f7eb2Smrg// permissions described in the GCC Runtime Library Exception, version 18627f7eb2Smrg// 3.1, as published by the Free Software Foundation. 19627f7eb2Smrg 20627f7eb2Smrg// You should have received a copy of the GNU General Public License and 21627f7eb2Smrg// a copy of the GCC Runtime Library Exception along with this program; 22627f7eb2Smrg// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23627f7eb2Smrg// <http://www.gnu.org/licenses/>. 24627f7eb2Smrg 25627f7eb2Smrg/** @file include/memory_resource 26627f7eb2Smrg * This is a Standard C++ Library header. 27627f7eb2Smrg */ 28627f7eb2Smrg 29627f7eb2Smrg#ifndef _GLIBCXX_MEMORY_RESOURCE 30627f7eb2Smrg#define _GLIBCXX_MEMORY_RESOURCE 1 31627f7eb2Smrg 32627f7eb2Smrg#pragma GCC system_header 33627f7eb2Smrg 34627f7eb2Smrg#if __cplusplus >= 201703L 35627f7eb2Smrg 36627f7eb2Smrg#include <memory> // align, allocator_arg_t, __uses_alloc 37627f7eb2Smrg#include <utility> // pair, index_sequence 38627f7eb2Smrg#include <vector> // vector 39627f7eb2Smrg#include <cstddef> // size_t, max_align_t, byte 40627f7eb2Smrg#include <shared_mutex> // shared_mutex 41627f7eb2Smrg#include <bits/functexcept.h> 42*4c3eb207Smrg#include <ext/numeric_traits.h> 43627f7eb2Smrg#include <debug/assertions.h> 44627f7eb2Smrg 45627f7eb2Smrgnamespace std _GLIBCXX_VISIBILITY(default) 46627f7eb2Smrg{ 47627f7eb2Smrg_GLIBCXX_BEGIN_NAMESPACE_VERSION 48627f7eb2Smrgnamespace pmr 49627f7eb2Smrg{ 50627f7eb2Smrg#ifdef _GLIBCXX_HAS_GTHREADS 51627f7eb2Smrg // Header and all contents are present. 52627f7eb2Smrg# define __cpp_lib_memory_resource 201603 53627f7eb2Smrg#else 54627f7eb2Smrg // The pmr::synchronized_pool_resource type is missing. 55627f7eb2Smrg# define __cpp_lib_memory_resource 1 56627f7eb2Smrg#endif 57627f7eb2Smrg 58627f7eb2Smrg class memory_resource; 59627f7eb2Smrg 60627f7eb2Smrg#if __cplusplus == 201703L 61627f7eb2Smrg template<typename _Tp> 62627f7eb2Smrg class polymorphic_allocator; 63627f7eb2Smrg#else // C++20 64*4c3eb207Smrg# define __cpp_lib_polymorphic_allocator 201902L 65627f7eb2Smrg template<typename _Tp = std::byte> 66627f7eb2Smrg class polymorphic_allocator; 67627f7eb2Smrg#endif 68627f7eb2Smrg 69627f7eb2Smrg // Global memory resources 70627f7eb2Smrg memory_resource* new_delete_resource() noexcept; 71627f7eb2Smrg memory_resource* null_memory_resource() noexcept; 72627f7eb2Smrg memory_resource* set_default_resource(memory_resource* __r) noexcept; 73627f7eb2Smrg memory_resource* get_default_resource() noexcept 74627f7eb2Smrg __attribute__((__returns_nonnull__)); 75627f7eb2Smrg 76627f7eb2Smrg // Pool resource classes 77627f7eb2Smrg struct pool_options; 78627f7eb2Smrg#ifdef _GLIBCXX_HAS_GTHREADS 79627f7eb2Smrg class synchronized_pool_resource; 80627f7eb2Smrg#endif 81627f7eb2Smrg class unsynchronized_pool_resource; 82627f7eb2Smrg class monotonic_buffer_resource; 83627f7eb2Smrg 84627f7eb2Smrg /// Class memory_resource 85627f7eb2Smrg class memory_resource 86627f7eb2Smrg { 87627f7eb2Smrg static constexpr size_t _S_max_align = alignof(max_align_t); 88627f7eb2Smrg 89627f7eb2Smrg public: 90627f7eb2Smrg memory_resource() = default; 91627f7eb2Smrg memory_resource(const memory_resource&) = default; 92627f7eb2Smrg virtual ~memory_resource(); // key function 93627f7eb2Smrg 94627f7eb2Smrg memory_resource& operator=(const memory_resource&) = default; 95627f7eb2Smrg 96627f7eb2Smrg [[nodiscard]] 97627f7eb2Smrg void* 98627f7eb2Smrg allocate(size_t __bytes, size_t __alignment = _S_max_align) 99627f7eb2Smrg __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3))) 100627f7eb2Smrg { return do_allocate(__bytes, __alignment); } 101627f7eb2Smrg 102627f7eb2Smrg void 103627f7eb2Smrg deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align) 104627f7eb2Smrg __attribute__((__nonnull__)) 105627f7eb2Smrg { return do_deallocate(__p, __bytes, __alignment); } 106627f7eb2Smrg 107627f7eb2Smrg bool 108627f7eb2Smrg is_equal(const memory_resource& __other) const noexcept 109627f7eb2Smrg { return do_is_equal(__other); } 110627f7eb2Smrg 111627f7eb2Smrg private: 112627f7eb2Smrg virtual void* 113627f7eb2Smrg do_allocate(size_t __bytes, size_t __alignment) = 0; 114627f7eb2Smrg 115627f7eb2Smrg virtual void 116627f7eb2Smrg do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0; 117627f7eb2Smrg 118627f7eb2Smrg virtual bool 119627f7eb2Smrg do_is_equal(const memory_resource& __other) const noexcept = 0; 120627f7eb2Smrg }; 121627f7eb2Smrg 122627f7eb2Smrg inline bool 123627f7eb2Smrg operator==(const memory_resource& __a, const memory_resource& __b) noexcept 124627f7eb2Smrg { return &__a == &__b || __a.is_equal(__b); } 125627f7eb2Smrg 126*4c3eb207Smrg#if __cpp_impl_three_way_comparison < 201907L 127627f7eb2Smrg inline bool 128627f7eb2Smrg operator!=(const memory_resource& __a, const memory_resource& __b) noexcept 129627f7eb2Smrg { return !(__a == __b); } 130*4c3eb207Smrg#endif 131627f7eb2Smrg 132627f7eb2Smrg // C++17 23.12.3 Class template polymorphic_allocator 133627f7eb2Smrg template<typename _Tp> 134627f7eb2Smrg class polymorphic_allocator 135627f7eb2Smrg { 136627f7eb2Smrg // _GLIBCXX_RESOLVE_LIB_DEFECTS 137627f7eb2Smrg // 2975. Missing case for pair construction in polymorphic allocators 138627f7eb2Smrg template<typename _Up> 139627f7eb2Smrg struct __not_pair { using type = void; }; 140627f7eb2Smrg 141627f7eb2Smrg template<typename _Up1, typename _Up2> 142627f7eb2Smrg struct __not_pair<pair<_Up1, _Up2>> { }; 143627f7eb2Smrg 144627f7eb2Smrg public: 145627f7eb2Smrg using value_type = _Tp; 146627f7eb2Smrg 147627f7eb2Smrg polymorphic_allocator() noexcept 148627f7eb2Smrg : _M_resource(get_default_resource()) 149627f7eb2Smrg { } 150627f7eb2Smrg 151627f7eb2Smrg polymorphic_allocator(memory_resource* __r) noexcept 152627f7eb2Smrg __attribute__((__nonnull__)) 153627f7eb2Smrg : _M_resource(__r) 154627f7eb2Smrg { _GLIBCXX_DEBUG_ASSERT(__r); } 155627f7eb2Smrg 156627f7eb2Smrg polymorphic_allocator(const polymorphic_allocator& __other) = default; 157627f7eb2Smrg 158627f7eb2Smrg template<typename _Up> 159627f7eb2Smrg polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept 160627f7eb2Smrg : _M_resource(__x.resource()) 161627f7eb2Smrg { } 162627f7eb2Smrg 163627f7eb2Smrg polymorphic_allocator& 164627f7eb2Smrg operator=(const polymorphic_allocator&) = delete; 165627f7eb2Smrg 166627f7eb2Smrg [[nodiscard]] 167627f7eb2Smrg _Tp* 168627f7eb2Smrg allocate(size_t __n) 169627f7eb2Smrg __attribute__((__returns_nonnull__)) 170627f7eb2Smrg { 171*4c3eb207Smrg if (__n > (__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Tp))) 172*4c3eb207Smrg _GLIBCXX_THROW_OR_ABORT(bad_array_new_length()); 173627f7eb2Smrg return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp), 174627f7eb2Smrg alignof(_Tp))); 175627f7eb2Smrg } 176627f7eb2Smrg 177627f7eb2Smrg void 178627f7eb2Smrg deallocate(_Tp* __p, size_t __n) noexcept 179627f7eb2Smrg __attribute__((__nonnull__)) 180627f7eb2Smrg { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } 181627f7eb2Smrg 182627f7eb2Smrg#if __cplusplus > 201703L 183*4c3eb207Smrg [[nodiscard]] void* 184627f7eb2Smrg allocate_bytes(size_t __nbytes, 185627f7eb2Smrg size_t __alignment = alignof(max_align_t)) 186627f7eb2Smrg { return _M_resource->allocate(__nbytes, __alignment); } 187627f7eb2Smrg 188627f7eb2Smrg void 189627f7eb2Smrg deallocate_bytes(void* __p, size_t __nbytes, 190627f7eb2Smrg size_t __alignment = alignof(max_align_t)) 191627f7eb2Smrg { _M_resource->deallocate(__p, __nbytes, __alignment); } 192627f7eb2Smrg 193627f7eb2Smrg template<typename _Up> 194*4c3eb207Smrg [[nodiscard]] _Up* 195627f7eb2Smrg allocate_object(size_t __n = 1) 196627f7eb2Smrg { 197*4c3eb207Smrg if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Up)) < __n) 198*4c3eb207Smrg _GLIBCXX_THROW_OR_ABORT(bad_array_new_length()); 199627f7eb2Smrg return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up), 200627f7eb2Smrg alignof(_Up))); 201627f7eb2Smrg } 202627f7eb2Smrg 203627f7eb2Smrg template<typename _Up> 204627f7eb2Smrg void 205627f7eb2Smrg deallocate_object(_Up* __p, size_t __n = 1) 206627f7eb2Smrg { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); } 207627f7eb2Smrg 208627f7eb2Smrg template<typename _Up, typename... _CtorArgs> 209*4c3eb207Smrg [[nodiscard]] _Up* 210627f7eb2Smrg new_object(_CtorArgs&&... __ctor_args) 211627f7eb2Smrg { 212627f7eb2Smrg _Up* __p = allocate_object<_Up>(); 213627f7eb2Smrg __try 214627f7eb2Smrg { 215627f7eb2Smrg construct(__p, std::forward<_CtorArgs>(__ctor_args)...); 216627f7eb2Smrg } 217627f7eb2Smrg __catch (...) 218627f7eb2Smrg { 219627f7eb2Smrg deallocate_object(__p); 220627f7eb2Smrg __throw_exception_again; 221627f7eb2Smrg } 222627f7eb2Smrg return __p; 223627f7eb2Smrg } 224627f7eb2Smrg 225627f7eb2Smrg template<typename _Up> 226627f7eb2Smrg void 227627f7eb2Smrg delete_object(_Up* __p) 228627f7eb2Smrg { 229627f7eb2Smrg destroy(__p); 230627f7eb2Smrg deallocate_object(__p); 231627f7eb2Smrg } 232627f7eb2Smrg#endif // C++2a 233627f7eb2Smrg 234627f7eb2Smrg#if __cplusplus == 201703L 235627f7eb2Smrg template<typename _Tp1, typename... _Args> 236627f7eb2Smrg __attribute__((__nonnull__)) 237627f7eb2Smrg typename __not_pair<_Tp1>::type 238627f7eb2Smrg construct(_Tp1* __p, _Args&&... __args) 239627f7eb2Smrg { 240627f7eb2Smrg // _GLIBCXX_RESOLVE_LIB_DEFECTS 241627f7eb2Smrg // 2969. polymorphic_allocator::construct() shouldn't pass resource() 242627f7eb2Smrg using __use_tag 243627f7eb2Smrg = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>; 244627f7eb2Smrg if constexpr (is_base_of_v<__uses_alloc0, __use_tag>) 245627f7eb2Smrg ::new(__p) _Tp1(std::forward<_Args>(__args)...); 246627f7eb2Smrg else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>) 247627f7eb2Smrg ::new(__p) _Tp1(allocator_arg, *this, 248627f7eb2Smrg std::forward<_Args>(__args)...); 249627f7eb2Smrg else 250627f7eb2Smrg ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this); 251627f7eb2Smrg } 252627f7eb2Smrg 253627f7eb2Smrg template<typename _Tp1, typename _Tp2, 254627f7eb2Smrg typename... _Args1, typename... _Args2> 255627f7eb2Smrg __attribute__((__nonnull__)) 256627f7eb2Smrg void 257627f7eb2Smrg construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t, 258627f7eb2Smrg tuple<_Args1...> __x, tuple<_Args2...> __y) 259627f7eb2Smrg { 260627f7eb2Smrg auto __x_tag = 261627f7eb2Smrg __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this); 262627f7eb2Smrg auto __y_tag = 263627f7eb2Smrg __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this); 264627f7eb2Smrg index_sequence_for<_Args1...> __x_i; 265627f7eb2Smrg index_sequence_for<_Args2...> __y_i; 266627f7eb2Smrg 267627f7eb2Smrg ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct, 268627f7eb2Smrg _S_construct_p(__x_tag, __x_i, __x), 269627f7eb2Smrg _S_construct_p(__y_tag, __y_i, __y)); 270627f7eb2Smrg } 271627f7eb2Smrg 272627f7eb2Smrg template<typename _Tp1, typename _Tp2> 273627f7eb2Smrg __attribute__((__nonnull__)) 274627f7eb2Smrg void 275627f7eb2Smrg construct(pair<_Tp1, _Tp2>* __p) 276627f7eb2Smrg { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); } 277627f7eb2Smrg 278627f7eb2Smrg template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 279627f7eb2Smrg __attribute__((__nonnull__)) 280627f7eb2Smrg void 281627f7eb2Smrg construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y) 282627f7eb2Smrg { 283627f7eb2Smrg this->construct(__p, piecewise_construct, 284627f7eb2Smrg forward_as_tuple(std::forward<_Up>(__x)), 285627f7eb2Smrg forward_as_tuple(std::forward<_Vp>(__y))); 286627f7eb2Smrg } 287627f7eb2Smrg 288627f7eb2Smrg template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 289627f7eb2Smrg __attribute__((__nonnull__)) 290627f7eb2Smrg void 291627f7eb2Smrg construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr) 292627f7eb2Smrg { 293627f7eb2Smrg this->construct(__p, piecewise_construct, 294627f7eb2Smrg forward_as_tuple(__pr.first), 295627f7eb2Smrg forward_as_tuple(__pr.second)); 296627f7eb2Smrg } 297627f7eb2Smrg 298627f7eb2Smrg template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 299627f7eb2Smrg __attribute__((__nonnull__)) 300627f7eb2Smrg void 301627f7eb2Smrg construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr) 302627f7eb2Smrg { 303627f7eb2Smrg this->construct(__p, piecewise_construct, 304627f7eb2Smrg forward_as_tuple(std::forward<_Up>(__pr.first)), 305627f7eb2Smrg forward_as_tuple(std::forward<_Vp>(__pr.second))); 306627f7eb2Smrg } 307627f7eb2Smrg#else 308627f7eb2Smrg template<typename _Tp1, typename... _Args> 309627f7eb2Smrg __attribute__((__nonnull__)) 310627f7eb2Smrg void 311627f7eb2Smrg construct(_Tp1* __p, _Args&&... __args) 312627f7eb2Smrg { 313627f7eb2Smrg std::uninitialized_construct_using_allocator(__p, *this, 314627f7eb2Smrg std::forward<_Args>(__args)...); 315627f7eb2Smrg } 316627f7eb2Smrg#endif 317627f7eb2Smrg 318627f7eb2Smrg template<typename _Up> 319627f7eb2Smrg __attribute__((__nonnull__)) 320627f7eb2Smrg void 321627f7eb2Smrg destroy(_Up* __p) 322627f7eb2Smrg { __p->~_Up(); } 323627f7eb2Smrg 324627f7eb2Smrg polymorphic_allocator 325627f7eb2Smrg select_on_container_copy_construction() const noexcept 326627f7eb2Smrg { return polymorphic_allocator(); } 327627f7eb2Smrg 328627f7eb2Smrg memory_resource* 329627f7eb2Smrg resource() const noexcept 330627f7eb2Smrg __attribute__((__returns_nonnull__)) 331627f7eb2Smrg { return _M_resource; } 332627f7eb2Smrg 333627f7eb2Smrg private: 334627f7eb2Smrg using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>; 335627f7eb2Smrg using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>; 336627f7eb2Smrg 337627f7eb2Smrg template<typename _Ind, typename... _Args> 338627f7eb2Smrg static tuple<_Args&&...> 339627f7eb2Smrg _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t) 340627f7eb2Smrg { return std::move(__t); } 341627f7eb2Smrg 342627f7eb2Smrg template<size_t... _Ind, typename... _Args> 343627f7eb2Smrg static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...> 344627f7eb2Smrg _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>, 345627f7eb2Smrg tuple<_Args...>& __t) 346627f7eb2Smrg { 347627f7eb2Smrg return { 348627f7eb2Smrg allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))... 349627f7eb2Smrg }; 350627f7eb2Smrg } 351627f7eb2Smrg 352627f7eb2Smrg template<size_t... _Ind, typename... _Args> 353627f7eb2Smrg static tuple<_Args&&..., polymorphic_allocator> 354627f7eb2Smrg _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>, 355627f7eb2Smrg tuple<_Args...>& __t) 356627f7eb2Smrg { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; } 357627f7eb2Smrg 358627f7eb2Smrg memory_resource* _M_resource; 359627f7eb2Smrg }; 360627f7eb2Smrg 361627f7eb2Smrg template<typename _Tp1, typename _Tp2> 362627f7eb2Smrg inline bool 363627f7eb2Smrg operator==(const polymorphic_allocator<_Tp1>& __a, 364627f7eb2Smrg const polymorphic_allocator<_Tp2>& __b) noexcept 365627f7eb2Smrg { return *__a.resource() == *__b.resource(); } 366627f7eb2Smrg 367*4c3eb207Smrg#if __cpp_impl_three_way_comparison < 201907L 368627f7eb2Smrg template<typename _Tp1, typename _Tp2> 369627f7eb2Smrg inline bool 370627f7eb2Smrg operator!=(const polymorphic_allocator<_Tp1>& __a, 371627f7eb2Smrg const polymorphic_allocator<_Tp2>& __b) noexcept 372627f7eb2Smrg { return !(__a == __b); } 373*4c3eb207Smrg#endif 374627f7eb2Smrg 375627f7eb2Smrg /// Parameters for tuning a pool resource's behaviour. 376627f7eb2Smrg struct pool_options 377627f7eb2Smrg { 378627f7eb2Smrg /** @brief Upper limit on number of blocks in a chunk. 379627f7eb2Smrg * 380627f7eb2Smrg * A lower value prevents allocating huge chunks that could remain mostly 381627f7eb2Smrg * unused, but means pools will need to replenished more frequently. 382627f7eb2Smrg */ 383627f7eb2Smrg size_t max_blocks_per_chunk = 0; 384627f7eb2Smrg 385627f7eb2Smrg /* @brief Largest block size (in bytes) that should be served from pools. 386627f7eb2Smrg * 387627f7eb2Smrg * Larger allocations will be served directly by the upstream resource, 388627f7eb2Smrg * not from one of the pools managed by the pool resource. 389627f7eb2Smrg */ 390627f7eb2Smrg size_t largest_required_pool_block = 0; 391627f7eb2Smrg }; 392627f7eb2Smrg 393627f7eb2Smrg // Common implementation details for un-/synchronized pool resources. 394627f7eb2Smrg class __pool_resource 395627f7eb2Smrg { 396627f7eb2Smrg friend class synchronized_pool_resource; 397627f7eb2Smrg friend class unsynchronized_pool_resource; 398627f7eb2Smrg 399627f7eb2Smrg __pool_resource(const pool_options& __opts, memory_resource* __upstream); 400627f7eb2Smrg 401627f7eb2Smrg ~__pool_resource(); 402627f7eb2Smrg 403627f7eb2Smrg __pool_resource(const __pool_resource&) = delete; 404627f7eb2Smrg __pool_resource& operator=(const __pool_resource&) = delete; 405627f7eb2Smrg 406627f7eb2Smrg // Allocate a large unpooled block. 407627f7eb2Smrg void* 408627f7eb2Smrg allocate(size_t __bytes, size_t __alignment); 409627f7eb2Smrg 410627f7eb2Smrg // Deallocate a large unpooled block. 411627f7eb2Smrg void 412627f7eb2Smrg deallocate(void* __p, size_t __bytes, size_t __alignment); 413627f7eb2Smrg 414627f7eb2Smrg 415627f7eb2Smrg // Deallocate unpooled memory. 416627f7eb2Smrg void release() noexcept; 417627f7eb2Smrg 418627f7eb2Smrg memory_resource* resource() const noexcept 419627f7eb2Smrg { return _M_unpooled.get_allocator().resource(); } 420627f7eb2Smrg 421627f7eb2Smrg struct _Pool; 422627f7eb2Smrg 423627f7eb2Smrg _Pool* _M_alloc_pools(); 424627f7eb2Smrg 425627f7eb2Smrg const pool_options _M_opts; 426627f7eb2Smrg 427627f7eb2Smrg struct _BigBlock; 428627f7eb2Smrg // Collection of blocks too big for any pool, sorted by address. 429627f7eb2Smrg // This also stores the only copy of the upstream memory resource pointer. 430627f7eb2Smrg _GLIBCXX_STD_C::pmr::vector<_BigBlock> _M_unpooled; 431627f7eb2Smrg 432627f7eb2Smrg const int _M_npools; 433627f7eb2Smrg }; 434627f7eb2Smrg 435627f7eb2Smrg#ifdef _GLIBCXX_HAS_GTHREADS 436627f7eb2Smrg /// A thread-safe memory resource that manages pools of fixed-size blocks. 437627f7eb2Smrg class synchronized_pool_resource : public memory_resource 438627f7eb2Smrg { 439627f7eb2Smrg public: 440627f7eb2Smrg synchronized_pool_resource(const pool_options& __opts, 441627f7eb2Smrg memory_resource* __upstream) 442627f7eb2Smrg __attribute__((__nonnull__)); 443627f7eb2Smrg 444627f7eb2Smrg synchronized_pool_resource() 445627f7eb2Smrg : synchronized_pool_resource(pool_options(), get_default_resource()) 446627f7eb2Smrg { } 447627f7eb2Smrg 448627f7eb2Smrg explicit 449627f7eb2Smrg synchronized_pool_resource(memory_resource* __upstream) 450627f7eb2Smrg __attribute__((__nonnull__)) 451627f7eb2Smrg : synchronized_pool_resource(pool_options(), __upstream) 452627f7eb2Smrg { } 453627f7eb2Smrg 454627f7eb2Smrg explicit 455627f7eb2Smrg synchronized_pool_resource(const pool_options& __opts) 456627f7eb2Smrg : synchronized_pool_resource(__opts, get_default_resource()) { } 457627f7eb2Smrg 458627f7eb2Smrg synchronized_pool_resource(const synchronized_pool_resource&) = delete; 459627f7eb2Smrg 460627f7eb2Smrg virtual ~synchronized_pool_resource(); 461627f7eb2Smrg 462627f7eb2Smrg synchronized_pool_resource& 463627f7eb2Smrg operator=(const synchronized_pool_resource&) = delete; 464627f7eb2Smrg 465627f7eb2Smrg void release(); 466627f7eb2Smrg 467627f7eb2Smrg memory_resource* 468627f7eb2Smrg upstream_resource() const noexcept 469627f7eb2Smrg __attribute__((__returns_nonnull__)) 470627f7eb2Smrg { return _M_impl.resource(); } 471627f7eb2Smrg 472627f7eb2Smrg pool_options options() const noexcept { return _M_impl._M_opts; } 473627f7eb2Smrg 474627f7eb2Smrg protected: 475627f7eb2Smrg void* 476627f7eb2Smrg do_allocate(size_t __bytes, size_t __alignment) override; 477627f7eb2Smrg 478627f7eb2Smrg void 479627f7eb2Smrg do_deallocate(void* __p, size_t __bytes, size_t __alignment) override; 480627f7eb2Smrg 481627f7eb2Smrg bool 482627f7eb2Smrg do_is_equal(const memory_resource& __other) const noexcept override 483627f7eb2Smrg { return this == &__other; } 484627f7eb2Smrg 485627f7eb2Smrg public: 486627f7eb2Smrg // Thread-specific pools (only public for access by implementation details) 487627f7eb2Smrg struct _TPools; 488627f7eb2Smrg 489627f7eb2Smrg private: 490627f7eb2Smrg _TPools* _M_alloc_tpools(lock_guard<shared_mutex>&); 491627f7eb2Smrg _TPools* _M_alloc_shared_tpools(lock_guard<shared_mutex>&); 492627f7eb2Smrg auto _M_thread_specific_pools() noexcept; 493627f7eb2Smrg 494627f7eb2Smrg __pool_resource _M_impl; 495627f7eb2Smrg __gthread_key_t _M_key; 496627f7eb2Smrg // Linked list of thread-specific pools. All threads share _M_tpools[0]. 497627f7eb2Smrg _TPools* _M_tpools = nullptr; 498627f7eb2Smrg mutable shared_mutex _M_mx; 499627f7eb2Smrg }; 500627f7eb2Smrg#endif 501627f7eb2Smrg 502627f7eb2Smrg /// A non-thread-safe memory resource that manages pools of fixed-size blocks. 503627f7eb2Smrg class unsynchronized_pool_resource : public memory_resource 504627f7eb2Smrg { 505627f7eb2Smrg public: 506627f7eb2Smrg [[__gnu__::__nonnull__]] 507627f7eb2Smrg unsynchronized_pool_resource(const pool_options& __opts, 508627f7eb2Smrg memory_resource* __upstream); 509627f7eb2Smrg 510627f7eb2Smrg unsynchronized_pool_resource() 511627f7eb2Smrg : unsynchronized_pool_resource(pool_options(), get_default_resource()) 512627f7eb2Smrg { } 513627f7eb2Smrg 514627f7eb2Smrg [[__gnu__::__nonnull__]] 515627f7eb2Smrg explicit 516627f7eb2Smrg unsynchronized_pool_resource(memory_resource* __upstream) 517627f7eb2Smrg : unsynchronized_pool_resource(pool_options(), __upstream) 518627f7eb2Smrg { } 519627f7eb2Smrg 520627f7eb2Smrg explicit 521627f7eb2Smrg unsynchronized_pool_resource(const pool_options& __opts) 522627f7eb2Smrg : unsynchronized_pool_resource(__opts, get_default_resource()) { } 523627f7eb2Smrg 524627f7eb2Smrg unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; 525627f7eb2Smrg 526627f7eb2Smrg virtual ~unsynchronized_pool_resource(); 527627f7eb2Smrg 528627f7eb2Smrg unsynchronized_pool_resource& 529627f7eb2Smrg operator=(const unsynchronized_pool_resource&) = delete; 530627f7eb2Smrg 531627f7eb2Smrg void release(); 532627f7eb2Smrg 533627f7eb2Smrg [[__gnu__::__returns_nonnull__]] 534627f7eb2Smrg memory_resource* 535627f7eb2Smrg upstream_resource() const noexcept 536627f7eb2Smrg { return _M_impl.resource(); } 537627f7eb2Smrg 538627f7eb2Smrg pool_options options() const noexcept { return _M_impl._M_opts; } 539627f7eb2Smrg 540627f7eb2Smrg protected: 541627f7eb2Smrg void* 542627f7eb2Smrg do_allocate(size_t __bytes, size_t __alignment) override; 543627f7eb2Smrg 544627f7eb2Smrg void 545627f7eb2Smrg do_deallocate(void* __p, size_t __bytes, size_t __alignment) override; 546627f7eb2Smrg 547627f7eb2Smrg bool 548627f7eb2Smrg do_is_equal(const memory_resource& __other) const noexcept override 549627f7eb2Smrg { return this == &__other; } 550627f7eb2Smrg 551627f7eb2Smrg private: 552627f7eb2Smrg using _Pool = __pool_resource::_Pool; 553627f7eb2Smrg 554627f7eb2Smrg auto _M_find_pool(size_t) noexcept; 555627f7eb2Smrg 556627f7eb2Smrg __pool_resource _M_impl; 557627f7eb2Smrg _Pool* _M_pools = nullptr; 558627f7eb2Smrg }; 559627f7eb2Smrg 560627f7eb2Smrg class monotonic_buffer_resource : public memory_resource 561627f7eb2Smrg { 562627f7eb2Smrg public: 563627f7eb2Smrg explicit 564627f7eb2Smrg monotonic_buffer_resource(memory_resource* __upstream) noexcept 565627f7eb2Smrg __attribute__((__nonnull__)) 566627f7eb2Smrg : _M_upstream(__upstream) 567627f7eb2Smrg { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); } 568627f7eb2Smrg 569627f7eb2Smrg monotonic_buffer_resource(size_t __initial_size, 570627f7eb2Smrg memory_resource* __upstream) noexcept 571627f7eb2Smrg __attribute__((__nonnull__)) 572627f7eb2Smrg : _M_next_bufsiz(__initial_size), 573627f7eb2Smrg _M_upstream(__upstream) 574627f7eb2Smrg { 575627f7eb2Smrg _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); 576627f7eb2Smrg _GLIBCXX_DEBUG_ASSERT(__initial_size > 0); 577627f7eb2Smrg } 578627f7eb2Smrg 579627f7eb2Smrg monotonic_buffer_resource(void* __buffer, size_t __buffer_size, 580627f7eb2Smrg memory_resource* __upstream) noexcept 581627f7eb2Smrg __attribute__((__nonnull__(4))) 582627f7eb2Smrg : _M_current_buf(__buffer), _M_avail(__buffer_size), 583627f7eb2Smrg _M_next_bufsiz(_S_next_bufsize(__buffer_size)), 584627f7eb2Smrg _M_upstream(__upstream), 585627f7eb2Smrg _M_orig_buf(__buffer), _M_orig_size(__buffer_size) 586627f7eb2Smrg { 587627f7eb2Smrg _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); 588627f7eb2Smrg _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0); 589627f7eb2Smrg } 590627f7eb2Smrg 591627f7eb2Smrg monotonic_buffer_resource() noexcept 592627f7eb2Smrg : monotonic_buffer_resource(get_default_resource()) 593627f7eb2Smrg { } 594627f7eb2Smrg 595627f7eb2Smrg explicit 596627f7eb2Smrg monotonic_buffer_resource(size_t __initial_size) noexcept 597627f7eb2Smrg : monotonic_buffer_resource(__initial_size, get_default_resource()) 598627f7eb2Smrg { } 599627f7eb2Smrg 600627f7eb2Smrg monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept 601627f7eb2Smrg : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource()) 602627f7eb2Smrg { } 603627f7eb2Smrg 604627f7eb2Smrg monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; 605627f7eb2Smrg 606627f7eb2Smrg virtual ~monotonic_buffer_resource(); // key function 607627f7eb2Smrg 608627f7eb2Smrg monotonic_buffer_resource& 609627f7eb2Smrg operator=(const monotonic_buffer_resource&) = delete; 610627f7eb2Smrg 611627f7eb2Smrg void 612627f7eb2Smrg release() noexcept 613627f7eb2Smrg { 614627f7eb2Smrg if (_M_head) 615627f7eb2Smrg _M_release_buffers(); 616627f7eb2Smrg 617627f7eb2Smrg // reset to initial state at contruction: 618627f7eb2Smrg if ((_M_current_buf = _M_orig_buf)) 619627f7eb2Smrg { 620627f7eb2Smrg _M_avail = _M_orig_size; 621627f7eb2Smrg _M_next_bufsiz = _S_next_bufsize(_M_orig_size); 622627f7eb2Smrg } 623627f7eb2Smrg else 624627f7eb2Smrg { 625627f7eb2Smrg _M_avail = 0; 626627f7eb2Smrg _M_next_bufsiz = _M_orig_size; 627627f7eb2Smrg } 628627f7eb2Smrg } 629627f7eb2Smrg 630627f7eb2Smrg memory_resource* 631627f7eb2Smrg upstream_resource() const noexcept 632627f7eb2Smrg __attribute__((__returns_nonnull__)) 633627f7eb2Smrg { return _M_upstream; } 634627f7eb2Smrg 635627f7eb2Smrg protected: 636627f7eb2Smrg void* 637627f7eb2Smrg do_allocate(size_t __bytes, size_t __alignment) override 638627f7eb2Smrg { 639627f7eb2Smrg if (__bytes == 0) 640627f7eb2Smrg __bytes = 1; // Ensures we don't return the same pointer twice. 641627f7eb2Smrg 642627f7eb2Smrg void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail); 643627f7eb2Smrg if (!__p) 644627f7eb2Smrg { 645627f7eb2Smrg _M_new_buffer(__bytes, __alignment); 646627f7eb2Smrg __p = _M_current_buf; 647627f7eb2Smrg } 648627f7eb2Smrg _M_current_buf = (char*)_M_current_buf + __bytes; 649627f7eb2Smrg _M_avail -= __bytes; 650627f7eb2Smrg return __p; 651627f7eb2Smrg } 652627f7eb2Smrg 653627f7eb2Smrg void 654627f7eb2Smrg do_deallocate(void*, size_t, size_t) override 655627f7eb2Smrg { } 656627f7eb2Smrg 657627f7eb2Smrg bool 658627f7eb2Smrg do_is_equal(const memory_resource& __other) const noexcept override 659627f7eb2Smrg { return this == &__other; } 660627f7eb2Smrg 661627f7eb2Smrg private: 662627f7eb2Smrg // Update _M_current_buf and _M_avail to refer to a new buffer with 663627f7eb2Smrg // at least the specified size and alignment, allocated from upstream. 664627f7eb2Smrg void 665627f7eb2Smrg _M_new_buffer(size_t __bytes, size_t __alignment); 666627f7eb2Smrg 667627f7eb2Smrg // Deallocate all buffers obtained from upstream. 668627f7eb2Smrg void 669627f7eb2Smrg _M_release_buffers() noexcept; 670627f7eb2Smrg 671627f7eb2Smrg static size_t 672627f7eb2Smrg _S_next_bufsize(size_t __buffer_size) noexcept 673627f7eb2Smrg { 674627f7eb2Smrg if (__buffer_size == 0) 675627f7eb2Smrg __buffer_size = 1; 676627f7eb2Smrg return __buffer_size * _S_growth_factor; 677627f7eb2Smrg } 678627f7eb2Smrg 679627f7eb2Smrg static constexpr size_t _S_init_bufsize = 128 * sizeof(void*); 680627f7eb2Smrg static constexpr float _S_growth_factor = 1.5; 681627f7eb2Smrg 682627f7eb2Smrg void* _M_current_buf = nullptr; 683627f7eb2Smrg size_t _M_avail = 0; 684627f7eb2Smrg size_t _M_next_bufsiz = _S_init_bufsize; 685627f7eb2Smrg 686627f7eb2Smrg // Initial values set at construction and reused by release(): 687627f7eb2Smrg memory_resource* const _M_upstream; 688627f7eb2Smrg void* const _M_orig_buf = nullptr; 689627f7eb2Smrg size_t const _M_orig_size = _M_next_bufsiz; 690627f7eb2Smrg 691627f7eb2Smrg class _Chunk; 692627f7eb2Smrg _Chunk* _M_head = nullptr; 693627f7eb2Smrg }; 694627f7eb2Smrg 695627f7eb2Smrg} // namespace pmr 696627f7eb2Smrg_GLIBCXX_END_NAMESPACE_VERSION 697627f7eb2Smrg} // namespace std 698627f7eb2Smrg 699627f7eb2Smrg#endif // C++17 700627f7eb2Smrg#endif // _GLIBCXX_MEMORY_RESOURCE 701