memory_resource 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. // <memory_resource> -*- C++ -*-
  2. // Copyright (C) 2018-2022 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the
  6. // terms of the GNU General Public License as published by the
  7. // Free Software Foundation; either version 3, or (at your option)
  8. // any later version.
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // Under Section 7 of GPL version 3, you are granted additional
  14. // permissions described in the GCC Runtime Library Exception, version
  15. // 3.1, as published by the Free Software Foundation.
  16. // You should have received a copy of the GNU General Public License and
  17. // a copy of the GCC Runtime Library Exception along with this program;
  18. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. // <http://www.gnu.org/licenses/>.
  20. /** @file include/memory_resource
  21. * This is a Standard C++ Library header.
  22. */
  23. #ifndef _GLIBCXX_MEMORY_RESOURCE
  24. #define _GLIBCXX_MEMORY_RESOURCE 1
  25. #pragma GCC system_header
  26. #if __cplusplus >= 201703L
  27. #include <new>
  28. #include <vector> // vector
  29. #include <cstddef> // size_t, max_align_t, byte
  30. #include <shared_mutex> // shared_mutex
  31. #include <bits/align.h> // align
  32. #include <bits/functexcept.h> // __throw_bad_array_new_length
  33. #include <bits/uses_allocator.h> // allocator_arg_t, __use_alloc
  34. #include <bits/uses_allocator_args.h> // uninitialized_construct_using_alloc
  35. #include <ext/numeric_traits.h>
  36. #include <debug/assertions.h>
  37. #if ! __cpp_lib_make_obj_using_allocator
  38. # include <bits/utility.h> // index_sequence
  39. # include <tuple> // tuple, forward_as_tuple
  40. #endif
  41. namespace std _GLIBCXX_VISIBILITY(default)
  42. {
  43. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  44. namespace pmr
  45. {
  46. #ifdef _GLIBCXX_HAS_GTHREADS
  47. // Header and all contents are present.
  48. # define __cpp_lib_memory_resource 201603L
  49. #else
  50. // The pmr::synchronized_pool_resource type is missing.
  51. # define __cpp_lib_memory_resource 1
  52. #endif
  53. class memory_resource;
  54. #if __cplusplus == 201703L
  55. template<typename _Tp>
  56. class polymorphic_allocator;
  57. #else // C++20
  58. # define __cpp_lib_polymorphic_allocator 201902L
  59. template<typename _Tp = std::byte>
  60. class polymorphic_allocator;
  61. #endif
  62. // Global memory resources
  63. memory_resource* new_delete_resource() noexcept;
  64. memory_resource* null_memory_resource() noexcept;
  65. memory_resource* set_default_resource(memory_resource* __r) noexcept;
  66. memory_resource* get_default_resource() noexcept
  67. __attribute__((__returns_nonnull__));
  68. // Pool resource classes
  69. struct pool_options;
  70. #ifdef _GLIBCXX_HAS_GTHREADS
  71. class synchronized_pool_resource;
  72. #endif
  73. class unsynchronized_pool_resource;
  74. class monotonic_buffer_resource;
  75. /// Class memory_resource
  76. class memory_resource
  77. {
  78. static constexpr size_t _S_max_align = alignof(max_align_t);
  79. public:
  80. memory_resource() = default;
  81. memory_resource(const memory_resource&) = default;
  82. virtual ~memory_resource(); // key function
  83. memory_resource& operator=(const memory_resource&) = default;
  84. [[nodiscard]]
  85. void*
  86. allocate(size_t __bytes, size_t __alignment = _S_max_align)
  87. __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3)))
  88. { return ::operator new(__bytes, do_allocate(__bytes, __alignment)); }
  89. void
  90. deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
  91. __attribute__((__nonnull__))
  92. { return do_deallocate(__p, __bytes, __alignment); }
  93. bool
  94. is_equal(const memory_resource& __other) const noexcept
  95. { return do_is_equal(__other); }
  96. private:
  97. virtual void*
  98. do_allocate(size_t __bytes, size_t __alignment) = 0;
  99. virtual void
  100. do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0;
  101. virtual bool
  102. do_is_equal(const memory_resource& __other) const noexcept = 0;
  103. };
  104. inline bool
  105. operator==(const memory_resource& __a, const memory_resource& __b) noexcept
  106. { return &__a == &__b || __a.is_equal(__b); }
  107. #if __cpp_impl_three_way_comparison < 201907L
  108. inline bool
  109. operator!=(const memory_resource& __a, const memory_resource& __b) noexcept
  110. { return !(__a == __b); }
  111. #endif
  112. // C++17 23.12.3 Class template polymorphic_allocator
  113. template<typename _Tp>
  114. class polymorphic_allocator
  115. {
  116. // _GLIBCXX_RESOLVE_LIB_DEFECTS
  117. // 2975. Missing case for pair construction in polymorphic allocators
  118. template<typename _Up>
  119. struct __not_pair { using type = void; };
  120. template<typename _Up1, typename _Up2>
  121. struct __not_pair<pair<_Up1, _Up2>> { };
  122. public:
  123. using value_type = _Tp;
  124. polymorphic_allocator() noexcept
  125. : _M_resource(get_default_resource())
  126. { }
  127. polymorphic_allocator(memory_resource* __r) noexcept
  128. __attribute__((__nonnull__))
  129. : _M_resource(__r)
  130. { _GLIBCXX_DEBUG_ASSERT(__r); }
  131. polymorphic_allocator(const polymorphic_allocator& __other) = default;
  132. template<typename _Up>
  133. polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept
  134. : _M_resource(__x.resource())
  135. { }
  136. polymorphic_allocator&
  137. operator=(const polymorphic_allocator&) = delete;
  138. [[nodiscard]]
  139. _Tp*
  140. allocate(size_t __n)
  141. __attribute__((__returns_nonnull__))
  142. {
  143. if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Tp)) < __n)
  144. std::__throw_bad_array_new_length();
  145. return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp),
  146. alignof(_Tp)));
  147. }
  148. void
  149. deallocate(_Tp* __p, size_t __n) noexcept
  150. __attribute__((__nonnull__))
  151. { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
  152. #if __cplusplus > 201703L
  153. [[nodiscard]] void*
  154. allocate_bytes(size_t __nbytes,
  155. size_t __alignment = alignof(max_align_t))
  156. { return _M_resource->allocate(__nbytes, __alignment); }
  157. void
  158. deallocate_bytes(void* __p, size_t __nbytes,
  159. size_t __alignment = alignof(max_align_t))
  160. { _M_resource->deallocate(__p, __nbytes, __alignment); }
  161. template<typename _Up>
  162. [[nodiscard]] _Up*
  163. allocate_object(size_t __n = 1)
  164. {
  165. if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Up)) < __n)
  166. std::__throw_bad_array_new_length();
  167. return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up),
  168. alignof(_Up)));
  169. }
  170. template<typename _Up>
  171. void
  172. deallocate_object(_Up* __p, size_t __n = 1)
  173. { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); }
  174. template<typename _Up, typename... _CtorArgs>
  175. [[nodiscard]] _Up*
  176. new_object(_CtorArgs&&... __ctor_args)
  177. {
  178. _Up* __p = allocate_object<_Up>();
  179. __try
  180. {
  181. construct(__p, std::forward<_CtorArgs>(__ctor_args)...);
  182. }
  183. __catch (...)
  184. {
  185. deallocate_object(__p);
  186. __throw_exception_again;
  187. }
  188. return __p;
  189. }
  190. template<typename _Up>
  191. void
  192. delete_object(_Up* __p)
  193. {
  194. __p->~_Up();
  195. deallocate_object(__p);
  196. }
  197. #endif // C++2a
  198. #if ! __cpp_lib_make_obj_using_allocator
  199. template<typename _Tp1, typename... _Args>
  200. __attribute__((__nonnull__))
  201. typename __not_pair<_Tp1>::type
  202. construct(_Tp1* __p, _Args&&... __args)
  203. {
  204. // _GLIBCXX_RESOLVE_LIB_DEFECTS
  205. // 2969. polymorphic_allocator::construct() shouldn't pass resource()
  206. using __use_tag
  207. = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>;
  208. if constexpr (is_base_of_v<__uses_alloc0, __use_tag>)
  209. ::new(__p) _Tp1(std::forward<_Args>(__args)...);
  210. else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>)
  211. ::new(__p) _Tp1(allocator_arg, *this,
  212. std::forward<_Args>(__args)...);
  213. else
  214. ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this);
  215. }
  216. template<typename _Tp1, typename _Tp2,
  217. typename... _Args1, typename... _Args2>
  218. __attribute__((__nonnull__))
  219. void
  220. construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t,
  221. tuple<_Args1...> __x, tuple<_Args2...> __y)
  222. {
  223. auto __x_tag =
  224. __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this);
  225. auto __y_tag =
  226. __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this);
  227. index_sequence_for<_Args1...> __x_i;
  228. index_sequence_for<_Args2...> __y_i;
  229. ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct,
  230. _S_construct_p(__x_tag, __x_i, __x),
  231. _S_construct_p(__y_tag, __y_i, __y));
  232. }
  233. template<typename _Tp1, typename _Tp2>
  234. __attribute__((__nonnull__))
  235. void
  236. construct(pair<_Tp1, _Tp2>* __p)
  237. { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
  238. template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
  239. __attribute__((__nonnull__))
  240. void
  241. construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y)
  242. {
  243. this->construct(__p, piecewise_construct,
  244. std::forward_as_tuple(std::forward<_Up>(__x)),
  245. std::forward_as_tuple(std::forward<_Vp>(__y)));
  246. }
  247. template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
  248. __attribute__((__nonnull__))
  249. void
  250. construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr)
  251. {
  252. this->construct(__p, piecewise_construct,
  253. std::forward_as_tuple(__pr.first),
  254. std::forward_as_tuple(__pr.second));
  255. }
  256. template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
  257. __attribute__((__nonnull__))
  258. void
  259. construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr)
  260. {
  261. this->construct(__p, piecewise_construct,
  262. std::forward_as_tuple(std::forward<_Up>(__pr.first)),
  263. std::forward_as_tuple(std::forward<_Vp>(__pr.second)));
  264. }
  265. #else // make_obj_using_allocator
  266. template<typename _Tp1, typename... _Args>
  267. __attribute__((__nonnull__))
  268. void
  269. construct(_Tp1* __p, _Args&&... __args)
  270. {
  271. std::uninitialized_construct_using_allocator(__p, *this,
  272. std::forward<_Args>(__args)...);
  273. }
  274. #endif
  275. template<typename _Up>
  276. _GLIBCXX20_DEPRECATED_SUGGEST("allocator_traits::destroy")
  277. __attribute__((__nonnull__))
  278. void
  279. destroy(_Up* __p)
  280. { __p->~_Up(); }
  281. polymorphic_allocator
  282. select_on_container_copy_construction() const noexcept
  283. { return polymorphic_allocator(); }
  284. memory_resource*
  285. resource() const noexcept
  286. __attribute__((__returns_nonnull__))
  287. { return _M_resource; }
  288. // _GLIBCXX_RESOLVE_LIB_DEFECTS
  289. // 3683. operator== for polymorphic_allocator cannot deduce template arg
  290. [[nodiscard]]
  291. friend bool
  292. operator==(const polymorphic_allocator& __a,
  293. const polymorphic_allocator& __b) noexcept
  294. { return *__a.resource() == *__b.resource(); }
  295. #if __cpp_impl_three_way_comparison < 201907L
  296. [[nodiscard]]
  297. friend bool
  298. operator!=(const polymorphic_allocator& __a,
  299. const polymorphic_allocator& __b) noexcept
  300. { return !(__a == __b); }
  301. #endif
  302. private:
  303. #if ! __cpp_lib_make_obj_using_allocator
  304. using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
  305. using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
  306. template<typename _Ind, typename... _Args>
  307. static tuple<_Args&&...>
  308. _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
  309. { return std::move(__t); }
  310. template<size_t... _Ind, typename... _Args>
  311. static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...>
  312. _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>,
  313. tuple<_Args...>& __t)
  314. {
  315. return {
  316. allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))...
  317. };
  318. }
  319. template<size_t... _Ind, typename... _Args>
  320. static tuple<_Args&&..., polymorphic_allocator>
  321. _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>,
  322. tuple<_Args...>& __t)
  323. { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; }
  324. #endif
  325. memory_resource* _M_resource;
  326. };
  327. template<typename _Tp1, typename _Tp2>
  328. inline bool
  329. operator==(const polymorphic_allocator<_Tp1>& __a,
  330. const polymorphic_allocator<_Tp2>& __b) noexcept
  331. { return *__a.resource() == *__b.resource(); }
  332. #if __cpp_impl_three_way_comparison < 201907L
  333. template<typename _Tp1, typename _Tp2>
  334. inline bool
  335. operator!=(const polymorphic_allocator<_Tp1>& __a,
  336. const polymorphic_allocator<_Tp2>& __b) noexcept
  337. { return !(__a == __b); }
  338. #endif
  339. } // namespace pmr
  340. /// Partial specialization for std::pmr::polymorphic_allocator
  341. template<typename _Tp>
  342. struct allocator_traits<pmr::polymorphic_allocator<_Tp>>
  343. {
  344. /// The allocator type
  345. using allocator_type = pmr::polymorphic_allocator<_Tp>;
  346. /// The allocated type
  347. using value_type = _Tp;
  348. /// The allocator's pointer type.
  349. using pointer = _Tp*;
  350. /// The allocator's const pointer type.
  351. using const_pointer = const _Tp*;
  352. /// The allocator's void pointer type.
  353. using void_pointer = void*;
  354. /// The allocator's const void pointer type.
  355. using const_void_pointer = const void*;
  356. /// The allocator's difference type
  357. using difference_type = std::ptrdiff_t;
  358. /// The allocator's size type
  359. using size_type = std::size_t;
  360. /** @{
  361. * A `polymorphic_allocator` does not propagate when a
  362. * container is copied, moved, or swapped.
  363. */
  364. using propagate_on_container_copy_assignment = false_type;
  365. using propagate_on_container_move_assignment = false_type;
  366. using propagate_on_container_swap = false_type;
  367. static allocator_type
  368. select_on_container_copy_construction(const allocator_type&) noexcept
  369. { return allocator_type(); }
  370. /// @}
  371. /// Whether all instances of the allocator type compare equal.
  372. using is_always_equal = false_type;
  373. template<typename _Up>
  374. using rebind_alloc = pmr::polymorphic_allocator<_Up>;
  375. template<typename _Up>
  376. using rebind_traits = allocator_traits<pmr::polymorphic_allocator<_Up>>;
  377. /**
  378. * @brief Allocate memory.
  379. * @param __a An allocator.
  380. * @param __n The number of objects to allocate space for.
  381. *
  382. * Calls `a.allocate(n)`.
  383. */
  384. [[nodiscard]] static pointer
  385. allocate(allocator_type& __a, size_type __n)
  386. { return __a.allocate(__n); }
  387. /**
  388. * @brief Allocate memory.
  389. * @param __a An allocator.
  390. * @param __n The number of objects to allocate space for.
  391. * @return Memory of suitable size and alignment for `n` objects
  392. * of type `value_type`.
  393. *
  394. * The third parameter is ignored..
  395. *
  396. * Returns `a.allocate(n)`.
  397. */
  398. [[nodiscard]] static pointer
  399. allocate(allocator_type& __a, size_type __n, const_void_pointer)
  400. { return __a.allocate(__n); }
  401. /**
  402. * @brief Deallocate memory.
  403. * @param __a An allocator.
  404. * @param __p Pointer to the memory to deallocate.
  405. * @param __n The number of objects space was allocated for.
  406. *
  407. * Calls `a.deallocate(p, n)`.
  408. */
  409. static void
  410. deallocate(allocator_type& __a, pointer __p, size_type __n)
  411. { __a.deallocate(__p, __n); }
  412. /**
  413. * @brief Construct an object of type `_Up`
  414. * @param __a An allocator.
  415. * @param __p Pointer to memory of suitable size and alignment for
  416. * an object of type `_Up`.
  417. * @param __args Constructor arguments.
  418. *
  419. * Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
  420. * in C++11, C++14 and C++17. Changed in C++20 to call
  421. * `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
  422. */
  423. template<typename _Up, typename... _Args>
  424. static void
  425. construct(allocator_type& __a, _Up* __p, _Args&&... __args)
  426. { __a.construct(__p, std::forward<_Args>(__args)...); }
  427. /**
  428. * @brief Destroy an object of type `_Up`
  429. * @param __a An allocator.
  430. * @param __p Pointer to the object to destroy
  431. *
  432. * Calls `p->_Up()`.
  433. */
  434. template<typename _Up>
  435. static _GLIBCXX20_CONSTEXPR void
  436. destroy(allocator_type&, _Up* __p)
  437. noexcept(is_nothrow_destructible<_Up>::value)
  438. { __p->~_Up(); }
  439. /**
  440. * @brief The maximum supported allocation size
  441. * @return `numeric_limits<size_t>::max() / sizeof(value_type)`
  442. */
  443. static _GLIBCXX20_CONSTEXPR size_type
  444. max_size(const allocator_type&) noexcept
  445. { return size_t(-1) / sizeof(value_type); }
  446. };
  447. namespace pmr
  448. {
  449. /// Parameters for tuning a pool resource's behaviour.
  450. struct pool_options
  451. {
  452. /** @brief Upper limit on number of blocks in a chunk.
  453. *
  454. * A lower value prevents allocating huge chunks that could remain mostly
  455. * unused, but means pools will need to replenished more frequently.
  456. */
  457. size_t max_blocks_per_chunk = 0;
  458. /* @brief Largest block size (in bytes) that should be served from pools.
  459. *
  460. * Larger allocations will be served directly by the upstream resource,
  461. * not from one of the pools managed by the pool resource.
  462. */
  463. size_t largest_required_pool_block = 0;
  464. };
  465. // Common implementation details for un-/synchronized pool resources.
  466. class __pool_resource
  467. {
  468. friend class synchronized_pool_resource;
  469. friend class unsynchronized_pool_resource;
  470. __pool_resource(const pool_options& __opts, memory_resource* __upstream);
  471. ~__pool_resource();
  472. __pool_resource(const __pool_resource&) = delete;
  473. __pool_resource& operator=(const __pool_resource&) = delete;
  474. // Allocate a large unpooled block.
  475. void*
  476. allocate(size_t __bytes, size_t __alignment);
  477. // Deallocate a large unpooled block.
  478. void
  479. deallocate(void* __p, size_t __bytes, size_t __alignment);
  480. // Deallocate unpooled memory.
  481. void release() noexcept;
  482. memory_resource* resource() const noexcept
  483. { return _M_unpooled.get_allocator().resource(); }
  484. struct _Pool;
  485. _Pool* _M_alloc_pools();
  486. const pool_options _M_opts;
  487. struct _BigBlock;
  488. // Collection of blocks too big for any pool, sorted by address.
  489. // This also stores the only copy of the upstream memory resource pointer.
  490. _GLIBCXX_STD_C::pmr::vector<_BigBlock> _M_unpooled;
  491. const int _M_npools;
  492. };
  493. #ifdef _GLIBCXX_HAS_GTHREADS
  494. /// A thread-safe memory resource that manages pools of fixed-size blocks.
  495. class synchronized_pool_resource : public memory_resource
  496. {
  497. public:
  498. synchronized_pool_resource(const pool_options& __opts,
  499. memory_resource* __upstream)
  500. __attribute__((__nonnull__));
  501. synchronized_pool_resource()
  502. : synchronized_pool_resource(pool_options(), get_default_resource())
  503. { }
  504. explicit
  505. synchronized_pool_resource(memory_resource* __upstream)
  506. __attribute__((__nonnull__))
  507. : synchronized_pool_resource(pool_options(), __upstream)
  508. { }
  509. explicit
  510. synchronized_pool_resource(const pool_options& __opts)
  511. : synchronized_pool_resource(__opts, get_default_resource()) { }
  512. synchronized_pool_resource(const synchronized_pool_resource&) = delete;
  513. virtual ~synchronized_pool_resource();
  514. synchronized_pool_resource&
  515. operator=(const synchronized_pool_resource&) = delete;
  516. void release();
  517. memory_resource*
  518. upstream_resource() const noexcept
  519. __attribute__((__returns_nonnull__))
  520. { return _M_impl.resource(); }
  521. pool_options options() const noexcept { return _M_impl._M_opts; }
  522. protected:
  523. void*
  524. do_allocate(size_t __bytes, size_t __alignment) override;
  525. void
  526. do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
  527. bool
  528. do_is_equal(const memory_resource& __other) const noexcept override
  529. { return this == &__other; }
  530. public:
  531. // Thread-specific pools (only public for access by implementation details)
  532. struct _TPools;
  533. private:
  534. _TPools* _M_alloc_tpools(lock_guard<shared_mutex>&);
  535. _TPools* _M_alloc_shared_tpools(lock_guard<shared_mutex>&);
  536. auto _M_thread_specific_pools() noexcept;
  537. __pool_resource _M_impl;
  538. __gthread_key_t _M_key;
  539. // Linked list of thread-specific pools. All threads share _M_tpools[0].
  540. _TPools* _M_tpools = nullptr;
  541. mutable shared_mutex _M_mx;
  542. };
  543. #endif
  544. /// A non-thread-safe memory resource that manages pools of fixed-size blocks.
  545. class unsynchronized_pool_resource : public memory_resource
  546. {
  547. public:
  548. [[__gnu__::__nonnull__]]
  549. unsynchronized_pool_resource(const pool_options& __opts,
  550. memory_resource* __upstream);
  551. unsynchronized_pool_resource()
  552. : unsynchronized_pool_resource(pool_options(), get_default_resource())
  553. { }
  554. [[__gnu__::__nonnull__]]
  555. explicit
  556. unsynchronized_pool_resource(memory_resource* __upstream)
  557. : unsynchronized_pool_resource(pool_options(), __upstream)
  558. { }
  559. explicit
  560. unsynchronized_pool_resource(const pool_options& __opts)
  561. : unsynchronized_pool_resource(__opts, get_default_resource()) { }
  562. unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
  563. virtual ~unsynchronized_pool_resource();
  564. unsynchronized_pool_resource&
  565. operator=(const unsynchronized_pool_resource&) = delete;
  566. void release();
  567. [[__gnu__::__returns_nonnull__]]
  568. memory_resource*
  569. upstream_resource() const noexcept
  570. { return _M_impl.resource(); }
  571. pool_options options() const noexcept { return _M_impl._M_opts; }
  572. protected:
  573. void*
  574. do_allocate(size_t __bytes, size_t __alignment) override;
  575. void
  576. do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
  577. bool
  578. do_is_equal(const memory_resource& __other) const noexcept override
  579. { return this == &__other; }
  580. private:
  581. using _Pool = __pool_resource::_Pool;
  582. auto _M_find_pool(size_t) noexcept;
  583. __pool_resource _M_impl;
  584. _Pool* _M_pools = nullptr;
  585. };
  586. class monotonic_buffer_resource : public memory_resource
  587. {
  588. public:
  589. explicit
  590. monotonic_buffer_resource(memory_resource* __upstream) noexcept
  591. __attribute__((__nonnull__))
  592. : _M_upstream(__upstream)
  593. { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); }
  594. monotonic_buffer_resource(size_t __initial_size,
  595. memory_resource* __upstream) noexcept
  596. __attribute__((__nonnull__))
  597. : _M_next_bufsiz(__initial_size),
  598. _M_upstream(__upstream)
  599. {
  600. _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
  601. _GLIBCXX_DEBUG_ASSERT(__initial_size > 0);
  602. }
  603. monotonic_buffer_resource(void* __buffer, size_t __buffer_size,
  604. memory_resource* __upstream) noexcept
  605. __attribute__((__nonnull__(4)))
  606. : _M_current_buf(__buffer), _M_avail(__buffer_size),
  607. _M_next_bufsiz(_S_next_bufsize(__buffer_size)),
  608. _M_upstream(__upstream),
  609. _M_orig_buf(__buffer), _M_orig_size(__buffer_size)
  610. {
  611. _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
  612. _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0);
  613. }
  614. monotonic_buffer_resource() noexcept
  615. : monotonic_buffer_resource(get_default_resource())
  616. { }
  617. explicit
  618. monotonic_buffer_resource(size_t __initial_size) noexcept
  619. : monotonic_buffer_resource(__initial_size, get_default_resource())
  620. { }
  621. monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept
  622. : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource())
  623. { }
  624. monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
  625. virtual ~monotonic_buffer_resource(); // key function
  626. monotonic_buffer_resource&
  627. operator=(const monotonic_buffer_resource&) = delete;
  628. void
  629. release() noexcept
  630. {
  631. if (_M_head)
  632. _M_release_buffers();
  633. // reset to initial state at contruction:
  634. if ((_M_current_buf = _M_orig_buf))
  635. {
  636. _M_avail = _M_orig_size;
  637. _M_next_bufsiz = _S_next_bufsize(_M_orig_size);
  638. }
  639. else
  640. {
  641. _M_avail = 0;
  642. _M_next_bufsiz = _M_orig_size;
  643. }
  644. }
  645. memory_resource*
  646. upstream_resource() const noexcept
  647. __attribute__((__returns_nonnull__))
  648. { return _M_upstream; }
  649. protected:
  650. void*
  651. do_allocate(size_t __bytes, size_t __alignment) override
  652. {
  653. if (__builtin_expect(__bytes == 0, false))
  654. __bytes = 1; // Ensures we don't return the same pointer twice.
  655. void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail);
  656. if (__builtin_expect(__p == nullptr, false))
  657. {
  658. _M_new_buffer(__bytes, __alignment);
  659. __p = _M_current_buf;
  660. }
  661. _M_current_buf = (char*)_M_current_buf + __bytes;
  662. _M_avail -= __bytes;
  663. return __p;
  664. }
  665. void
  666. do_deallocate(void*, size_t, size_t) override
  667. { }
  668. bool
  669. do_is_equal(const memory_resource& __other) const noexcept override
  670. { return this == &__other; }
  671. private:
  672. // Update _M_current_buf and _M_avail to refer to a new buffer with
  673. // at least the specified size and alignment, allocated from upstream.
  674. void
  675. _M_new_buffer(size_t __bytes, size_t __alignment);
  676. // Deallocate all buffers obtained from upstream.
  677. void
  678. _M_release_buffers() noexcept;
  679. static size_t
  680. _S_next_bufsize(size_t __buffer_size) noexcept
  681. {
  682. if (__builtin_expect(__buffer_size == 0, false))
  683. __buffer_size = 1;
  684. return __buffer_size * _S_growth_factor;
  685. }
  686. static constexpr size_t _S_init_bufsize = 128 * sizeof(void*);
  687. static constexpr float _S_growth_factor = 1.5;
  688. void* _M_current_buf = nullptr;
  689. size_t _M_avail = 0;
  690. size_t _M_next_bufsiz = _S_init_bufsize;
  691. // Initial values set at construction and reused by release():
  692. memory_resource* const _M_upstream;
  693. void* const _M_orig_buf = nullptr;
  694. size_t const _M_orig_size = _M_next_bufsiz;
  695. class _Chunk;
  696. _Chunk* _M_head = nullptr;
  697. };
  698. } // namespace pmr
  699. _GLIBCXX_END_NAMESPACE_VERSION
  700. } // namespace std
  701. #endif // C++17
  702. #endif // _GLIBCXX_MEMORY_RESOURCE