1181254a7Smrg// <memory_resource> -*- C++ -*- 2181254a7Smrg 3*b1e83836Smrg// Copyright (C) 2018-2022 Free Software Foundation, Inc. 4181254a7Smrg// 5181254a7Smrg// This file is part of the GNU ISO C++ Library. This library is free 6181254a7Smrg// software; you can redistribute it and/or modify it under the 7181254a7Smrg// terms of the GNU General Public License as published by the 8181254a7Smrg// Free Software Foundation; either version 3, or (at your option) 9181254a7Smrg// any later version. 10181254a7Smrg 11181254a7Smrg// This library is distributed in the hope that it will be useful, 12181254a7Smrg// but WITHOUT ANY WARRANTY; without even the implied warranty of 13181254a7Smrg// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14181254a7Smrg// GNU General Public License for more details. 15181254a7Smrg 16181254a7Smrg// Under Section 7 of GPL version 3, you are granted additional 17181254a7Smrg// permissions described in the GCC Runtime Library Exception, version 18181254a7Smrg// 3.1, as published by the Free Software Foundation. 19181254a7Smrg 20181254a7Smrg// You should have received a copy of the GNU General Public License and 21181254a7Smrg// a copy of the GCC Runtime Library Exception along with this program; 22181254a7Smrg// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23181254a7Smrg// <http://www.gnu.org/licenses/>. 24181254a7Smrg 25181254a7Smrg/** @file include/memory_resource 26181254a7Smrg * This is a Standard C++ Library header. 27181254a7Smrg */ 28181254a7Smrg 29181254a7Smrg#ifndef _GLIBCXX_MEMORY_RESOURCE 30181254a7Smrg#define _GLIBCXX_MEMORY_RESOURCE 1 31181254a7Smrg 32181254a7Smrg#pragma GCC system_header 33181254a7Smrg 34181254a7Smrg#if __cplusplus >= 201703L 35181254a7Smrg 36*b1e83836Smrg#include <new> 37181254a7Smrg#include <vector> // vector 38181254a7Smrg#include <cstddef> // size_t, max_align_t, byte 39181254a7Smrg#include <shared_mutex> // shared_mutex 40*b1e83836Smrg#include <bits/align.h> // align 41*b1e83836Smrg#include <bits/functexcept.h> // __throw_bad_array_new_length 42*b1e83836Smrg#include <bits/uses_allocator.h> // allocator_arg_t, __use_alloc 43*b1e83836Smrg#include <bits/uses_allocator_args.h> // uninitialized_construct_using_alloc 44fb8a8121Smrg#include <ext/numeric_traits.h> 45181254a7Smrg#include <debug/assertions.h> 46181254a7Smrg 47*b1e83836Smrg#if ! __cpp_lib_make_obj_using_allocator 48*b1e83836Smrg# include <bits/utility.h> // index_sequence 49*b1e83836Smrg# include <tuple> // tuple, forward_as_tuple 50*b1e83836Smrg#endif 51*b1e83836Smrg 52181254a7Smrgnamespace std _GLIBCXX_VISIBILITY(default) 53181254a7Smrg{ 54181254a7Smrg_GLIBCXX_BEGIN_NAMESPACE_VERSION 55181254a7Smrgnamespace pmr 56181254a7Smrg{ 57181254a7Smrg#ifdef _GLIBCXX_HAS_GTHREADS 58181254a7Smrg // Header and all contents are present. 59*b1e83836Smrg# define __cpp_lib_memory_resource 201603L 60181254a7Smrg#else 61181254a7Smrg // The pmr::synchronized_pool_resource type is missing. 62181254a7Smrg# define __cpp_lib_memory_resource 1 63181254a7Smrg#endif 64181254a7Smrg 65181254a7Smrg class memory_resource; 66181254a7Smrg 67181254a7Smrg#if __cplusplus == 201703L 68181254a7Smrg template<typename _Tp> 69181254a7Smrg class polymorphic_allocator; 70181254a7Smrg#else // C++20 71fb8a8121Smrg# define __cpp_lib_polymorphic_allocator 201902L 72181254a7Smrg template<typename _Tp = std::byte> 73181254a7Smrg class polymorphic_allocator; 74181254a7Smrg#endif 75181254a7Smrg 76181254a7Smrg // Global memory resources 77*b1e83836Smrg 78*b1e83836Smrg /// A pmr::memory_resource that uses `new` to allocate memory 79*b1e83836Smrg [[nodiscard, __gnu__::__returns_nonnull__, __gnu__::__const__]] 80*b1e83836Smrg memory_resource* 81*b1e83836Smrg new_delete_resource() noexcept; 82*b1e83836Smrg 83*b1e83836Smrg /// A pmr::memory_resource that always throws `bad_alloc` 84*b1e83836Smrg [[nodiscard, __gnu__::__returns_nonnull__, __gnu__::__const__]] 85*b1e83836Smrg memory_resource* 86*b1e83836Smrg null_memory_resource() noexcept; 87*b1e83836Smrg 88*b1e83836Smrg /// Replace the default memory resource pointer 89*b1e83836Smrg [[__gnu__::__returns_nonnull__]] 90*b1e83836Smrg memory_resource* 91*b1e83836Smrg set_default_resource(memory_resource* __r) noexcept; 92*b1e83836Smrg 93*b1e83836Smrg /// Get the current default memory resource pointer 94*b1e83836Smrg [[__gnu__::__returns_nonnull__]] 95*b1e83836Smrg memory_resource* 96*b1e83836Smrg get_default_resource() noexcept; 97181254a7Smrg 98181254a7Smrg // Pool resource classes 99181254a7Smrg struct pool_options; 100181254a7Smrg#ifdef _GLIBCXX_HAS_GTHREADS 101181254a7Smrg class synchronized_pool_resource; 102181254a7Smrg#endif 103181254a7Smrg class unsynchronized_pool_resource; 104181254a7Smrg class monotonic_buffer_resource; 105181254a7Smrg 106181254a7Smrg /// Class memory_resource 107181254a7Smrg class memory_resource 108181254a7Smrg { 109181254a7Smrg static constexpr size_t _S_max_align = alignof(max_align_t); 110181254a7Smrg 111181254a7Smrg public: 112181254a7Smrg memory_resource() = default; 113181254a7Smrg memory_resource(const memory_resource&) = default; 114181254a7Smrg virtual ~memory_resource(); // key function 115181254a7Smrg 116181254a7Smrg memory_resource& operator=(const memory_resource&) = default; 117181254a7Smrg 118181254a7Smrg [[nodiscard]] 119181254a7Smrg void* 120181254a7Smrg allocate(size_t __bytes, size_t __alignment = _S_max_align) 121181254a7Smrg __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3))) 122*b1e83836Smrg { return ::operator new(__bytes, do_allocate(__bytes, __alignment)); } 123181254a7Smrg 124181254a7Smrg void 125181254a7Smrg deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align) 126181254a7Smrg __attribute__((__nonnull__)) 127181254a7Smrg { return do_deallocate(__p, __bytes, __alignment); } 128181254a7Smrg 129*b1e83836Smrg [[nodiscard]] 130181254a7Smrg bool 131181254a7Smrg is_equal(const memory_resource& __other) const noexcept 132181254a7Smrg { return do_is_equal(__other); } 133181254a7Smrg 134181254a7Smrg private: 135181254a7Smrg virtual void* 136181254a7Smrg do_allocate(size_t __bytes, size_t __alignment) = 0; 137181254a7Smrg 138181254a7Smrg virtual void 139181254a7Smrg do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0; 140181254a7Smrg 141181254a7Smrg virtual bool 142181254a7Smrg do_is_equal(const memory_resource& __other) const noexcept = 0; 143181254a7Smrg }; 144181254a7Smrg 145*b1e83836Smrg [[nodiscard]] 146181254a7Smrg inline bool 147181254a7Smrg operator==(const memory_resource& __a, const memory_resource& __b) noexcept 148181254a7Smrg { return &__a == &__b || __a.is_equal(__b); } 149181254a7Smrg 150fb8a8121Smrg#if __cpp_impl_three_way_comparison < 201907L 151*b1e83836Smrg [[nodiscard]] 152181254a7Smrg inline bool 153181254a7Smrg operator!=(const memory_resource& __a, const memory_resource& __b) noexcept 154181254a7Smrg { return !(__a == __b); } 155fb8a8121Smrg#endif 156181254a7Smrg 157181254a7Smrg // C++17 23.12.3 Class template polymorphic_allocator 158181254a7Smrg template<typename _Tp> 159181254a7Smrg class polymorphic_allocator 160181254a7Smrg { 161181254a7Smrg // _GLIBCXX_RESOLVE_LIB_DEFECTS 162181254a7Smrg // 2975. Missing case for pair construction in polymorphic allocators 163181254a7Smrg template<typename _Up> 164181254a7Smrg struct __not_pair { using type = void; }; 165181254a7Smrg 166181254a7Smrg template<typename _Up1, typename _Up2> 167181254a7Smrg struct __not_pair<pair<_Up1, _Up2>> { }; 168181254a7Smrg 169181254a7Smrg public: 170181254a7Smrg using value_type = _Tp; 171181254a7Smrg 172181254a7Smrg polymorphic_allocator() noexcept 173181254a7Smrg : _M_resource(get_default_resource()) 174181254a7Smrg { } 175181254a7Smrg 176181254a7Smrg polymorphic_allocator(memory_resource* __r) noexcept 177181254a7Smrg __attribute__((__nonnull__)) 178181254a7Smrg : _M_resource(__r) 179181254a7Smrg { _GLIBCXX_DEBUG_ASSERT(__r); } 180181254a7Smrg 181181254a7Smrg polymorphic_allocator(const polymorphic_allocator& __other) = default; 182181254a7Smrg 183181254a7Smrg template<typename _Up> 184181254a7Smrg polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept 185181254a7Smrg : _M_resource(__x.resource()) 186181254a7Smrg { } 187181254a7Smrg 188181254a7Smrg polymorphic_allocator& 189181254a7Smrg operator=(const polymorphic_allocator&) = delete; 190181254a7Smrg 191181254a7Smrg [[nodiscard]] 192181254a7Smrg _Tp* 193181254a7Smrg allocate(size_t __n) 194181254a7Smrg __attribute__((__returns_nonnull__)) 195181254a7Smrg { 196*b1e83836Smrg if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Tp)) < __n) 197*b1e83836Smrg std::__throw_bad_array_new_length(); 198181254a7Smrg return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp), 199181254a7Smrg alignof(_Tp))); 200181254a7Smrg } 201181254a7Smrg 202181254a7Smrg void 203181254a7Smrg deallocate(_Tp* __p, size_t __n) noexcept 204181254a7Smrg __attribute__((__nonnull__)) 205181254a7Smrg { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } 206181254a7Smrg 207181254a7Smrg#if __cplusplus > 201703L 208fb8a8121Smrg [[nodiscard]] void* 209181254a7Smrg allocate_bytes(size_t __nbytes, 210181254a7Smrg size_t __alignment = alignof(max_align_t)) 211181254a7Smrg { return _M_resource->allocate(__nbytes, __alignment); } 212181254a7Smrg 213181254a7Smrg void 214181254a7Smrg deallocate_bytes(void* __p, size_t __nbytes, 215181254a7Smrg size_t __alignment = alignof(max_align_t)) 216181254a7Smrg { _M_resource->deallocate(__p, __nbytes, __alignment); } 217181254a7Smrg 218181254a7Smrg template<typename _Up> 219fb8a8121Smrg [[nodiscard]] _Up* 220181254a7Smrg allocate_object(size_t __n = 1) 221181254a7Smrg { 222fb8a8121Smrg if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Up)) < __n) 223*b1e83836Smrg std::__throw_bad_array_new_length(); 224181254a7Smrg return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up), 225181254a7Smrg alignof(_Up))); 226181254a7Smrg } 227181254a7Smrg 228181254a7Smrg template<typename _Up> 229181254a7Smrg void 230181254a7Smrg deallocate_object(_Up* __p, size_t __n = 1) 231181254a7Smrg { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); } 232181254a7Smrg 233181254a7Smrg template<typename _Up, typename... _CtorArgs> 234fb8a8121Smrg [[nodiscard]] _Up* 235181254a7Smrg new_object(_CtorArgs&&... __ctor_args) 236181254a7Smrg { 237181254a7Smrg _Up* __p = allocate_object<_Up>(); 238181254a7Smrg __try 239181254a7Smrg { 240181254a7Smrg construct(__p, std::forward<_CtorArgs>(__ctor_args)...); 241181254a7Smrg } 242181254a7Smrg __catch (...) 243181254a7Smrg { 244181254a7Smrg deallocate_object(__p); 245181254a7Smrg __throw_exception_again; 246181254a7Smrg } 247181254a7Smrg return __p; 248181254a7Smrg } 249181254a7Smrg 250181254a7Smrg template<typename _Up> 251181254a7Smrg void 252181254a7Smrg delete_object(_Up* __p) 253181254a7Smrg { 254*b1e83836Smrg __p->~_Up(); 255181254a7Smrg deallocate_object(__p); 256181254a7Smrg } 257181254a7Smrg#endif // C++2a 258181254a7Smrg 259*b1e83836Smrg#if ! __cpp_lib_make_obj_using_allocator 260181254a7Smrg template<typename _Tp1, typename... _Args> 261181254a7Smrg __attribute__((__nonnull__)) 262181254a7Smrg typename __not_pair<_Tp1>::type 263181254a7Smrg construct(_Tp1* __p, _Args&&... __args) 264181254a7Smrg { 265181254a7Smrg // _GLIBCXX_RESOLVE_LIB_DEFECTS 266181254a7Smrg // 2969. polymorphic_allocator::construct() shouldn't pass resource() 267181254a7Smrg using __use_tag 268181254a7Smrg = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>; 269181254a7Smrg if constexpr (is_base_of_v<__uses_alloc0, __use_tag>) 270181254a7Smrg ::new(__p) _Tp1(std::forward<_Args>(__args)...); 271181254a7Smrg else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>) 272181254a7Smrg ::new(__p) _Tp1(allocator_arg, *this, 273181254a7Smrg std::forward<_Args>(__args)...); 274181254a7Smrg else 275181254a7Smrg ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this); 276181254a7Smrg } 277181254a7Smrg 278181254a7Smrg template<typename _Tp1, typename _Tp2, 279181254a7Smrg typename... _Args1, typename... _Args2> 280181254a7Smrg __attribute__((__nonnull__)) 281181254a7Smrg void 282181254a7Smrg construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t, 283181254a7Smrg tuple<_Args1...> __x, tuple<_Args2...> __y) 284181254a7Smrg { 285181254a7Smrg auto __x_tag = 286181254a7Smrg __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this); 287181254a7Smrg auto __y_tag = 288181254a7Smrg __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this); 289181254a7Smrg index_sequence_for<_Args1...> __x_i; 290181254a7Smrg index_sequence_for<_Args2...> __y_i; 291181254a7Smrg 292181254a7Smrg ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct, 293181254a7Smrg _S_construct_p(__x_tag, __x_i, __x), 294181254a7Smrg _S_construct_p(__y_tag, __y_i, __y)); 295181254a7Smrg } 296181254a7Smrg 297181254a7Smrg template<typename _Tp1, typename _Tp2> 298181254a7Smrg __attribute__((__nonnull__)) 299181254a7Smrg void 300181254a7Smrg construct(pair<_Tp1, _Tp2>* __p) 301181254a7Smrg { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); } 302181254a7Smrg 303181254a7Smrg template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 304181254a7Smrg __attribute__((__nonnull__)) 305181254a7Smrg void 306181254a7Smrg construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y) 307181254a7Smrg { 308181254a7Smrg this->construct(__p, piecewise_construct, 309*b1e83836Smrg std::forward_as_tuple(std::forward<_Up>(__x)), 310*b1e83836Smrg std::forward_as_tuple(std::forward<_Vp>(__y))); 311181254a7Smrg } 312181254a7Smrg 313181254a7Smrg template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 314181254a7Smrg __attribute__((__nonnull__)) 315181254a7Smrg void 316181254a7Smrg construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr) 317181254a7Smrg { 318181254a7Smrg this->construct(__p, piecewise_construct, 319*b1e83836Smrg std::forward_as_tuple(__pr.first), 320*b1e83836Smrg std::forward_as_tuple(__pr.second)); 321181254a7Smrg } 322181254a7Smrg 323181254a7Smrg template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp> 324181254a7Smrg __attribute__((__nonnull__)) 325181254a7Smrg void 326181254a7Smrg construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr) 327181254a7Smrg { 328181254a7Smrg this->construct(__p, piecewise_construct, 329*b1e83836Smrg std::forward_as_tuple(std::forward<_Up>(__pr.first)), 330*b1e83836Smrg std::forward_as_tuple(std::forward<_Vp>(__pr.second))); 331181254a7Smrg } 332*b1e83836Smrg#else // make_obj_using_allocator 333181254a7Smrg template<typename _Tp1, typename... _Args> 334181254a7Smrg __attribute__((__nonnull__)) 335181254a7Smrg void 336181254a7Smrg construct(_Tp1* __p, _Args&&... __args) 337181254a7Smrg { 338181254a7Smrg std::uninitialized_construct_using_allocator(__p, *this, 339181254a7Smrg std::forward<_Args>(__args)...); 340181254a7Smrg } 341181254a7Smrg#endif 342181254a7Smrg 343181254a7Smrg template<typename _Up> 344*b1e83836Smrg _GLIBCXX20_DEPRECATED_SUGGEST("allocator_traits::destroy") 345181254a7Smrg __attribute__((__nonnull__)) 346181254a7Smrg void 347181254a7Smrg destroy(_Up* __p) 348181254a7Smrg { __p->~_Up(); } 349181254a7Smrg 350181254a7Smrg polymorphic_allocator 351181254a7Smrg select_on_container_copy_construction() const noexcept 352181254a7Smrg { return polymorphic_allocator(); } 353181254a7Smrg 354181254a7Smrg memory_resource* 355181254a7Smrg resource() const noexcept 356181254a7Smrg __attribute__((__returns_nonnull__)) 357181254a7Smrg { return _M_resource; } 358181254a7Smrg 359*b1e83836Smrg // _GLIBCXX_RESOLVE_LIB_DEFECTS 360*b1e83836Smrg // 3683. operator== for polymorphic_allocator cannot deduce template arg 361*b1e83836Smrg [[nodiscard]] 362*b1e83836Smrg friend bool 363*b1e83836Smrg operator==(const polymorphic_allocator& __a, 364*b1e83836Smrg const polymorphic_allocator& __b) noexcept 365*b1e83836Smrg { return *__a.resource() == *__b.resource(); } 366*b1e83836Smrg 367*b1e83836Smrg#if __cpp_impl_three_way_comparison < 201907L 368*b1e83836Smrg [[nodiscard]] 369*b1e83836Smrg friend bool 370*b1e83836Smrg operator!=(const polymorphic_allocator& __a, 371*b1e83836Smrg const polymorphic_allocator& __b) noexcept 372*b1e83836Smrg { return !(__a == __b); } 373*b1e83836Smrg#endif 374*b1e83836Smrg 375181254a7Smrg private: 376*b1e83836Smrg#if ! __cpp_lib_make_obj_using_allocator 377181254a7Smrg using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>; 378181254a7Smrg using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>; 379181254a7Smrg 380181254a7Smrg template<typename _Ind, typename... _Args> 381181254a7Smrg static tuple<_Args&&...> 382181254a7Smrg _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t) 383181254a7Smrg { return std::move(__t); } 384181254a7Smrg 385181254a7Smrg template<size_t... _Ind, typename... _Args> 386181254a7Smrg static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...> 387181254a7Smrg _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>, 388181254a7Smrg tuple<_Args...>& __t) 389181254a7Smrg { 390181254a7Smrg return { 391181254a7Smrg allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))... 392181254a7Smrg }; 393181254a7Smrg } 394181254a7Smrg 395181254a7Smrg template<size_t... _Ind, typename... _Args> 396181254a7Smrg static tuple<_Args&&..., polymorphic_allocator> 397181254a7Smrg _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>, 398181254a7Smrg tuple<_Args...>& __t) 399181254a7Smrg { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; } 400*b1e83836Smrg#endif 401181254a7Smrg 402181254a7Smrg memory_resource* _M_resource; 403181254a7Smrg }; 404181254a7Smrg 405181254a7Smrg template<typename _Tp1, typename _Tp2> 406*b1e83836Smrg [[nodiscard]] 407181254a7Smrg inline bool 408181254a7Smrg operator==(const polymorphic_allocator<_Tp1>& __a, 409181254a7Smrg const polymorphic_allocator<_Tp2>& __b) noexcept 410181254a7Smrg { return *__a.resource() == *__b.resource(); } 411181254a7Smrg 412fb8a8121Smrg#if __cpp_impl_three_way_comparison < 201907L 413181254a7Smrg template<typename _Tp1, typename _Tp2> 414*b1e83836Smrg [[nodiscard]] 415181254a7Smrg inline bool 416181254a7Smrg operator!=(const polymorphic_allocator<_Tp1>& __a, 417181254a7Smrg const polymorphic_allocator<_Tp2>& __b) noexcept 418181254a7Smrg { return !(__a == __b); } 419fb8a8121Smrg#endif 420181254a7Smrg 421*b1e83836Smrg} // namespace pmr 422*b1e83836Smrg 423*b1e83836Smrg /// Partial specialization for std::pmr::polymorphic_allocator 424*b1e83836Smrg template<typename _Tp> 425*b1e83836Smrg struct allocator_traits<pmr::polymorphic_allocator<_Tp>> 426*b1e83836Smrg { 427*b1e83836Smrg /// The allocator type 428*b1e83836Smrg using allocator_type = pmr::polymorphic_allocator<_Tp>; 429*b1e83836Smrg 430*b1e83836Smrg /// The allocated type 431*b1e83836Smrg using value_type = _Tp; 432*b1e83836Smrg 433*b1e83836Smrg /// The allocator's pointer type. 434*b1e83836Smrg using pointer = _Tp*; 435*b1e83836Smrg 436*b1e83836Smrg /// The allocator's const pointer type. 437*b1e83836Smrg using const_pointer = const _Tp*; 438*b1e83836Smrg 439*b1e83836Smrg /// The allocator's void pointer type. 440*b1e83836Smrg using void_pointer = void*; 441*b1e83836Smrg 442*b1e83836Smrg /// The allocator's const void pointer type. 443*b1e83836Smrg using const_void_pointer = const void*; 444*b1e83836Smrg 445*b1e83836Smrg /// The allocator's difference type 446*b1e83836Smrg using difference_type = std::ptrdiff_t; 447*b1e83836Smrg 448*b1e83836Smrg /// The allocator's size type 449*b1e83836Smrg using size_type = std::size_t; 450*b1e83836Smrg 451*b1e83836Smrg /** @{ 452*b1e83836Smrg * A `polymorphic_allocator` does not propagate when a 453*b1e83836Smrg * container is copied, moved, or swapped. 454*b1e83836Smrg */ 455*b1e83836Smrg using propagate_on_container_copy_assignment = false_type; 456*b1e83836Smrg using propagate_on_container_move_assignment = false_type; 457*b1e83836Smrg using propagate_on_container_swap = false_type; 458*b1e83836Smrg 459*b1e83836Smrg static allocator_type 460*b1e83836Smrg select_on_container_copy_construction(const allocator_type&) noexcept 461*b1e83836Smrg { return allocator_type(); } 462*b1e83836Smrg /// @} 463*b1e83836Smrg 464*b1e83836Smrg /// Whether all instances of the allocator type compare equal. 465*b1e83836Smrg using is_always_equal = false_type; 466*b1e83836Smrg 467*b1e83836Smrg template<typename _Up> 468*b1e83836Smrg using rebind_alloc = pmr::polymorphic_allocator<_Up>; 469*b1e83836Smrg 470*b1e83836Smrg template<typename _Up> 471*b1e83836Smrg using rebind_traits = allocator_traits<pmr::polymorphic_allocator<_Up>>; 472*b1e83836Smrg 473*b1e83836Smrg /** 474*b1e83836Smrg * @brief Allocate memory. 475*b1e83836Smrg * @param __a An allocator. 476*b1e83836Smrg * @param __n The number of objects to allocate space for. 477*b1e83836Smrg * 478*b1e83836Smrg * Calls `a.allocate(n)`. 479*b1e83836Smrg */ 480*b1e83836Smrg [[nodiscard]] static pointer 481*b1e83836Smrg allocate(allocator_type& __a, size_type __n) 482*b1e83836Smrg { return __a.allocate(__n); } 483*b1e83836Smrg 484*b1e83836Smrg /** 485*b1e83836Smrg * @brief Allocate memory. 486*b1e83836Smrg * @param __a An allocator. 487*b1e83836Smrg * @param __n The number of objects to allocate space for. 488*b1e83836Smrg * @return Memory of suitable size and alignment for `n` objects 489*b1e83836Smrg * of type `value_type`. 490*b1e83836Smrg * 491*b1e83836Smrg * The third parameter is ignored.. 492*b1e83836Smrg * 493*b1e83836Smrg * Returns `a.allocate(n)`. 494*b1e83836Smrg */ 495*b1e83836Smrg [[nodiscard]] static pointer 496*b1e83836Smrg allocate(allocator_type& __a, size_type __n, const_void_pointer) 497*b1e83836Smrg { return __a.allocate(__n); } 498*b1e83836Smrg 499*b1e83836Smrg /** 500*b1e83836Smrg * @brief Deallocate memory. 501*b1e83836Smrg * @param __a An allocator. 502*b1e83836Smrg * @param __p Pointer to the memory to deallocate. 503*b1e83836Smrg * @param __n The number of objects space was allocated for. 504*b1e83836Smrg * 505*b1e83836Smrg * Calls `a.deallocate(p, n)`. 506*b1e83836Smrg */ 507*b1e83836Smrg static void 508*b1e83836Smrg deallocate(allocator_type& __a, pointer __p, size_type __n) 509*b1e83836Smrg { __a.deallocate(__p, __n); } 510*b1e83836Smrg 511*b1e83836Smrg /** 512*b1e83836Smrg * @brief Construct an object of type `_Up` 513*b1e83836Smrg * @param __a An allocator. 514*b1e83836Smrg * @param __p Pointer to memory of suitable size and alignment for 515*b1e83836Smrg * an object of type `_Up`. 516*b1e83836Smrg * @param __args Constructor arguments. 517*b1e83836Smrg * 518*b1e83836Smrg * Calls `__a.construct(__p, std::forward<_Args>(__args)...)` 519*b1e83836Smrg * in C++11, C++14 and C++17. Changed in C++20 to call 520*b1e83836Smrg * `std::construct_at(__p, std::forward<_Args>(__args)...)` instead. 521*b1e83836Smrg */ 522*b1e83836Smrg template<typename _Up, typename... _Args> 523*b1e83836Smrg static void 524*b1e83836Smrg construct(allocator_type& __a, _Up* __p, _Args&&... __args) 525*b1e83836Smrg { __a.construct(__p, std::forward<_Args>(__args)...); } 526*b1e83836Smrg 527*b1e83836Smrg /** 528*b1e83836Smrg * @brief Destroy an object of type `_Up` 529*b1e83836Smrg * @param __a An allocator. 530*b1e83836Smrg * @param __p Pointer to the object to destroy 531*b1e83836Smrg * 532*b1e83836Smrg * Calls `p->_Up()`. 533*b1e83836Smrg */ 534*b1e83836Smrg template<typename _Up> 535*b1e83836Smrg static _GLIBCXX20_CONSTEXPR void 536*b1e83836Smrg destroy(allocator_type&, _Up* __p) 537*b1e83836Smrg noexcept(is_nothrow_destructible<_Up>::value) 538*b1e83836Smrg { __p->~_Up(); } 539*b1e83836Smrg 540*b1e83836Smrg /** 541*b1e83836Smrg * @brief The maximum supported allocation size 542*b1e83836Smrg * @return `numeric_limits<size_t>::max() / sizeof(value_type)` 543*b1e83836Smrg */ 544*b1e83836Smrg static _GLIBCXX20_CONSTEXPR size_type 545*b1e83836Smrg max_size(const allocator_type&) noexcept 546*b1e83836Smrg { return size_t(-1) / sizeof(value_type); } 547*b1e83836Smrg }; 548*b1e83836Smrg 549*b1e83836Smrgnamespace pmr 550*b1e83836Smrg{ 551181254a7Smrg /// Parameters for tuning a pool resource's behaviour. 552181254a7Smrg struct pool_options 553181254a7Smrg { 554181254a7Smrg /** @brief Upper limit on number of blocks in a chunk. 555181254a7Smrg * 556181254a7Smrg * A lower value prevents allocating huge chunks that could remain mostly 557181254a7Smrg * unused, but means pools will need to replenished more frequently. 558181254a7Smrg */ 559181254a7Smrg size_t max_blocks_per_chunk = 0; 560181254a7Smrg 561181254a7Smrg /* @brief Largest block size (in bytes) that should be served from pools. 562181254a7Smrg * 563181254a7Smrg * Larger allocations will be served directly by the upstream resource, 564181254a7Smrg * not from one of the pools managed by the pool resource. 565181254a7Smrg */ 566181254a7Smrg size_t largest_required_pool_block = 0; 567181254a7Smrg }; 568181254a7Smrg 569181254a7Smrg // Common implementation details for un-/synchronized pool resources. 570181254a7Smrg class __pool_resource 571181254a7Smrg { 572181254a7Smrg friend class synchronized_pool_resource; 573181254a7Smrg friend class unsynchronized_pool_resource; 574181254a7Smrg 575181254a7Smrg __pool_resource(const pool_options& __opts, memory_resource* __upstream); 576181254a7Smrg 577181254a7Smrg ~__pool_resource(); 578181254a7Smrg 579181254a7Smrg __pool_resource(const __pool_resource&) = delete; 580181254a7Smrg __pool_resource& operator=(const __pool_resource&) = delete; 581181254a7Smrg 582181254a7Smrg // Allocate a large unpooled block. 583181254a7Smrg void* 584181254a7Smrg allocate(size_t __bytes, size_t __alignment); 585181254a7Smrg 586181254a7Smrg // Deallocate a large unpooled block. 587181254a7Smrg void 588181254a7Smrg deallocate(void* __p, size_t __bytes, size_t __alignment); 589181254a7Smrg 590181254a7Smrg 591181254a7Smrg // Deallocate unpooled memory. 592181254a7Smrg void release() noexcept; 593181254a7Smrg 594181254a7Smrg memory_resource* resource() const noexcept 595181254a7Smrg { return _M_unpooled.get_allocator().resource(); } 596181254a7Smrg 597181254a7Smrg struct _Pool; 598181254a7Smrg 599181254a7Smrg _Pool* _M_alloc_pools(); 600181254a7Smrg 601181254a7Smrg const pool_options _M_opts; 602181254a7Smrg 603181254a7Smrg struct _BigBlock; 604181254a7Smrg // Collection of blocks too big for any pool, sorted by address. 605181254a7Smrg // This also stores the only copy of the upstream memory resource pointer. 606181254a7Smrg _GLIBCXX_STD_C::pmr::vector<_BigBlock> _M_unpooled; 607181254a7Smrg 608181254a7Smrg const int _M_npools; 609181254a7Smrg }; 610181254a7Smrg 611181254a7Smrg#ifdef _GLIBCXX_HAS_GTHREADS 612181254a7Smrg /// A thread-safe memory resource that manages pools of fixed-size blocks. 613181254a7Smrg class synchronized_pool_resource : public memory_resource 614181254a7Smrg { 615181254a7Smrg public: 616181254a7Smrg synchronized_pool_resource(const pool_options& __opts, 617181254a7Smrg memory_resource* __upstream) 618181254a7Smrg __attribute__((__nonnull__)); 619181254a7Smrg 620181254a7Smrg synchronized_pool_resource() 621181254a7Smrg : synchronized_pool_resource(pool_options(), get_default_resource()) 622181254a7Smrg { } 623181254a7Smrg 624181254a7Smrg explicit 625181254a7Smrg synchronized_pool_resource(memory_resource* __upstream) 626181254a7Smrg __attribute__((__nonnull__)) 627181254a7Smrg : synchronized_pool_resource(pool_options(), __upstream) 628181254a7Smrg { } 629181254a7Smrg 630181254a7Smrg explicit 631181254a7Smrg synchronized_pool_resource(const pool_options& __opts) 632181254a7Smrg : synchronized_pool_resource(__opts, get_default_resource()) { } 633181254a7Smrg 634181254a7Smrg synchronized_pool_resource(const synchronized_pool_resource&) = delete; 635181254a7Smrg 636181254a7Smrg virtual ~synchronized_pool_resource(); 637181254a7Smrg 638181254a7Smrg synchronized_pool_resource& 639181254a7Smrg operator=(const synchronized_pool_resource&) = delete; 640181254a7Smrg 641181254a7Smrg void release(); 642181254a7Smrg 643181254a7Smrg memory_resource* 644181254a7Smrg upstream_resource() const noexcept 645181254a7Smrg __attribute__((__returns_nonnull__)) 646181254a7Smrg { return _M_impl.resource(); } 647181254a7Smrg 648181254a7Smrg pool_options options() const noexcept { return _M_impl._M_opts; } 649181254a7Smrg 650181254a7Smrg protected: 651181254a7Smrg void* 652181254a7Smrg do_allocate(size_t __bytes, size_t __alignment) override; 653181254a7Smrg 654181254a7Smrg void 655181254a7Smrg do_deallocate(void* __p, size_t __bytes, size_t __alignment) override; 656181254a7Smrg 657181254a7Smrg bool 658181254a7Smrg do_is_equal(const memory_resource& __other) const noexcept override 659181254a7Smrg { return this == &__other; } 660181254a7Smrg 661181254a7Smrg public: 662181254a7Smrg // Thread-specific pools (only public for access by implementation details) 663181254a7Smrg struct _TPools; 664181254a7Smrg 665181254a7Smrg private: 666181254a7Smrg _TPools* _M_alloc_tpools(lock_guard<shared_mutex>&); 667181254a7Smrg _TPools* _M_alloc_shared_tpools(lock_guard<shared_mutex>&); 668181254a7Smrg auto _M_thread_specific_pools() noexcept; 669181254a7Smrg 670181254a7Smrg __pool_resource _M_impl; 671181254a7Smrg __gthread_key_t _M_key; 672181254a7Smrg // Linked list of thread-specific pools. All threads share _M_tpools[0]. 673181254a7Smrg _TPools* _M_tpools = nullptr; 674181254a7Smrg mutable shared_mutex _M_mx; 675181254a7Smrg }; 676181254a7Smrg#endif 677181254a7Smrg 678181254a7Smrg /// A non-thread-safe memory resource that manages pools of fixed-size blocks. 679181254a7Smrg class unsynchronized_pool_resource : public memory_resource 680181254a7Smrg { 681181254a7Smrg public: 682181254a7Smrg [[__gnu__::__nonnull__]] 683181254a7Smrg unsynchronized_pool_resource(const pool_options& __opts, 684181254a7Smrg memory_resource* __upstream); 685181254a7Smrg 686181254a7Smrg unsynchronized_pool_resource() 687181254a7Smrg : unsynchronized_pool_resource(pool_options(), get_default_resource()) 688181254a7Smrg { } 689181254a7Smrg 690181254a7Smrg [[__gnu__::__nonnull__]] 691181254a7Smrg explicit 692181254a7Smrg unsynchronized_pool_resource(memory_resource* __upstream) 693181254a7Smrg : unsynchronized_pool_resource(pool_options(), __upstream) 694181254a7Smrg { } 695181254a7Smrg 696181254a7Smrg explicit 697181254a7Smrg unsynchronized_pool_resource(const pool_options& __opts) 698181254a7Smrg : unsynchronized_pool_resource(__opts, get_default_resource()) { } 699181254a7Smrg 700181254a7Smrg unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; 701181254a7Smrg 702181254a7Smrg virtual ~unsynchronized_pool_resource(); 703181254a7Smrg 704181254a7Smrg unsynchronized_pool_resource& 705181254a7Smrg operator=(const unsynchronized_pool_resource&) = delete; 706181254a7Smrg 707181254a7Smrg void release(); 708181254a7Smrg 709181254a7Smrg [[__gnu__::__returns_nonnull__]] 710181254a7Smrg memory_resource* 711181254a7Smrg upstream_resource() const noexcept 712181254a7Smrg { return _M_impl.resource(); } 713181254a7Smrg 714181254a7Smrg pool_options options() const noexcept { return _M_impl._M_opts; } 715181254a7Smrg 716181254a7Smrg protected: 717181254a7Smrg void* 718181254a7Smrg do_allocate(size_t __bytes, size_t __alignment) override; 719181254a7Smrg 720181254a7Smrg void 721181254a7Smrg do_deallocate(void* __p, size_t __bytes, size_t __alignment) override; 722181254a7Smrg 723181254a7Smrg bool 724181254a7Smrg do_is_equal(const memory_resource& __other) const noexcept override 725181254a7Smrg { return this == &__other; } 726181254a7Smrg 727181254a7Smrg private: 728181254a7Smrg using _Pool = __pool_resource::_Pool; 729181254a7Smrg 730181254a7Smrg auto _M_find_pool(size_t) noexcept; 731181254a7Smrg 732181254a7Smrg __pool_resource _M_impl; 733181254a7Smrg _Pool* _M_pools = nullptr; 734181254a7Smrg }; 735181254a7Smrg 736181254a7Smrg class monotonic_buffer_resource : public memory_resource 737181254a7Smrg { 738181254a7Smrg public: 739181254a7Smrg explicit 740181254a7Smrg monotonic_buffer_resource(memory_resource* __upstream) noexcept 741181254a7Smrg __attribute__((__nonnull__)) 742181254a7Smrg : _M_upstream(__upstream) 743181254a7Smrg { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); } 744181254a7Smrg 745181254a7Smrg monotonic_buffer_resource(size_t __initial_size, 746181254a7Smrg memory_resource* __upstream) noexcept 747181254a7Smrg __attribute__((__nonnull__)) 748181254a7Smrg : _M_next_bufsiz(__initial_size), 749181254a7Smrg _M_upstream(__upstream) 750181254a7Smrg { 751181254a7Smrg _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); 752181254a7Smrg _GLIBCXX_DEBUG_ASSERT(__initial_size > 0); 753181254a7Smrg } 754181254a7Smrg 755181254a7Smrg monotonic_buffer_resource(void* __buffer, size_t __buffer_size, 756181254a7Smrg memory_resource* __upstream) noexcept 757181254a7Smrg __attribute__((__nonnull__(4))) 758181254a7Smrg : _M_current_buf(__buffer), _M_avail(__buffer_size), 759181254a7Smrg _M_next_bufsiz(_S_next_bufsize(__buffer_size)), 760181254a7Smrg _M_upstream(__upstream), 761181254a7Smrg _M_orig_buf(__buffer), _M_orig_size(__buffer_size) 762181254a7Smrg { 763181254a7Smrg _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); 764181254a7Smrg _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0); 765181254a7Smrg } 766181254a7Smrg 767181254a7Smrg monotonic_buffer_resource() noexcept 768181254a7Smrg : monotonic_buffer_resource(get_default_resource()) 769181254a7Smrg { } 770181254a7Smrg 771181254a7Smrg explicit 772181254a7Smrg monotonic_buffer_resource(size_t __initial_size) noexcept 773181254a7Smrg : monotonic_buffer_resource(__initial_size, get_default_resource()) 774181254a7Smrg { } 775181254a7Smrg 776181254a7Smrg monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept 777181254a7Smrg : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource()) 778181254a7Smrg { } 779181254a7Smrg 780181254a7Smrg monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; 781181254a7Smrg 782181254a7Smrg virtual ~monotonic_buffer_resource(); // key function 783181254a7Smrg 784181254a7Smrg monotonic_buffer_resource& 785181254a7Smrg operator=(const monotonic_buffer_resource&) = delete; 786181254a7Smrg 787181254a7Smrg void 788181254a7Smrg release() noexcept 789181254a7Smrg { 790181254a7Smrg if (_M_head) 791181254a7Smrg _M_release_buffers(); 792181254a7Smrg 793181254a7Smrg // reset to initial state at contruction: 794181254a7Smrg if ((_M_current_buf = _M_orig_buf)) 795181254a7Smrg { 796181254a7Smrg _M_avail = _M_orig_size; 797181254a7Smrg _M_next_bufsiz = _S_next_bufsize(_M_orig_size); 798181254a7Smrg } 799181254a7Smrg else 800181254a7Smrg { 801181254a7Smrg _M_avail = 0; 802181254a7Smrg _M_next_bufsiz = _M_orig_size; 803181254a7Smrg } 804181254a7Smrg } 805181254a7Smrg 806181254a7Smrg memory_resource* 807181254a7Smrg upstream_resource() const noexcept 808181254a7Smrg __attribute__((__returns_nonnull__)) 809181254a7Smrg { return _M_upstream; } 810181254a7Smrg 811181254a7Smrg protected: 812181254a7Smrg void* 813181254a7Smrg do_allocate(size_t __bytes, size_t __alignment) override 814181254a7Smrg { 815*b1e83836Smrg if (__builtin_expect(__bytes == 0, false)) 816181254a7Smrg __bytes = 1; // Ensures we don't return the same pointer twice. 817181254a7Smrg 818181254a7Smrg void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail); 819*b1e83836Smrg if (__builtin_expect(__p == nullptr, false)) 820181254a7Smrg { 821181254a7Smrg _M_new_buffer(__bytes, __alignment); 822181254a7Smrg __p = _M_current_buf; 823181254a7Smrg } 824181254a7Smrg _M_current_buf = (char*)_M_current_buf + __bytes; 825181254a7Smrg _M_avail -= __bytes; 826181254a7Smrg return __p; 827181254a7Smrg } 828181254a7Smrg 829181254a7Smrg void 830181254a7Smrg do_deallocate(void*, size_t, size_t) override 831181254a7Smrg { } 832181254a7Smrg 833181254a7Smrg bool 834181254a7Smrg do_is_equal(const memory_resource& __other) const noexcept override 835181254a7Smrg { return this == &__other; } 836181254a7Smrg 837181254a7Smrg private: 838181254a7Smrg // Update _M_current_buf and _M_avail to refer to a new buffer with 839181254a7Smrg // at least the specified size and alignment, allocated from upstream. 840181254a7Smrg void 841181254a7Smrg _M_new_buffer(size_t __bytes, size_t __alignment); 842181254a7Smrg 843181254a7Smrg // Deallocate all buffers obtained from upstream. 844181254a7Smrg void 845181254a7Smrg _M_release_buffers() noexcept; 846181254a7Smrg 847181254a7Smrg static size_t 848181254a7Smrg _S_next_bufsize(size_t __buffer_size) noexcept 849181254a7Smrg { 850*b1e83836Smrg if (__builtin_expect(__buffer_size == 0, false)) 851181254a7Smrg __buffer_size = 1; 852181254a7Smrg return __buffer_size * _S_growth_factor; 853181254a7Smrg } 854181254a7Smrg 855181254a7Smrg static constexpr size_t _S_init_bufsize = 128 * sizeof(void*); 856181254a7Smrg static constexpr float _S_growth_factor = 1.5; 857181254a7Smrg 858181254a7Smrg void* _M_current_buf = nullptr; 859181254a7Smrg size_t _M_avail = 0; 860181254a7Smrg size_t _M_next_bufsiz = _S_init_bufsize; 861181254a7Smrg 862181254a7Smrg // Initial values set at construction and reused by release(): 863181254a7Smrg memory_resource* const _M_upstream; 864181254a7Smrg void* const _M_orig_buf = nullptr; 865181254a7Smrg size_t const _M_orig_size = _M_next_bufsiz; 866181254a7Smrg 867181254a7Smrg class _Chunk; 868181254a7Smrg _Chunk* _M_head = nullptr; 869181254a7Smrg }; 870181254a7Smrg 871181254a7Smrg} // namespace pmr 872181254a7Smrg_GLIBCXX_END_NAMESPACE_VERSION 873181254a7Smrg} // namespace std 874181254a7Smrg 875181254a7Smrg#endif // C++17 876181254a7Smrg#endif // _GLIBCXX_MEMORY_RESOURCE 877