memory_resource 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. // <memory_resource> -*- C++ -*-
  2. // Copyright (C) 2018-2021 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 <vector> // vector
  28. #include <cstddef> // size_t, max_align_t, byte
  29. #include <shared_mutex> // shared_mutex
  30. #include <bits/align.h> // align
  31. #include <bits/functexcept.h> // __throw_bad_array_new_length
  32. #include <bits/uses_allocator.h> // __use_alloc
  33. #include <bits/uses_allocator_args.h> // uninitialized_construct_using_alloc
  34. #include <ext/numeric_traits.h>
  35. #include <debug/assertions.h>
  36. #if ! __cpp_lib_make_obj_using_allocator
  37. # include <utility> // pair, index_sequence
  38. # include <tuple> // tuple, forward_as_tuple
  39. #endif
  40. namespace std _GLIBCXX_VISIBILITY(default)
  41. {
  42. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  43. namespace pmr
  44. {
  45. #ifdef _GLIBCXX_HAS_GTHREADS
  46. // Header and all contents are present.
  47. # define __cpp_lib_memory_resource 201603L
  48. #else
  49. // The pmr::synchronized_pool_resource type is missing.
  50. # define __cpp_lib_memory_resource 1
  51. #endif
  52. class memory_resource;
  53. #if __cplusplus == 201703L
  54. template<typename _Tp>
  55. class polymorphic_allocator;
  56. #else // C++20
  57. # define __cpp_lib_polymorphic_allocator 201902L
  58. template<typename _Tp = std::byte>
  59. class polymorphic_allocator;
  60. #endif
  61. // Global memory resources
  62. memory_resource* new_delete_resource() noexcept;
  63. memory_resource* null_memory_resource() noexcept;
  64. memory_resource* set_default_resource(memory_resource* __r) noexcept;
  65. memory_resource* get_default_resource() noexcept
  66. __attribute__((__returns_nonnull__));
  67. // Pool resource classes
  68. struct pool_options;
  69. #ifdef _GLIBCXX_HAS_GTHREADS
  70. class synchronized_pool_resource;
  71. #endif
  72. class unsynchronized_pool_resource;
  73. class monotonic_buffer_resource;
  74. /// Class memory_resource
  75. class memory_resource
  76. {
  77. static constexpr size_t _S_max_align = alignof(max_align_t);
  78. public:
  79. memory_resource() = default;
  80. memory_resource(const memory_resource&) = default;
  81. virtual ~memory_resource(); // key function
  82. memory_resource& operator=(const memory_resource&) = default;
  83. [[nodiscard]]
  84. void*
  85. allocate(size_t __bytes, size_t __alignment = _S_max_align)
  86. __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3)))
  87. { return do_allocate(__bytes, __alignment); }
  88. void
  89. deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
  90. __attribute__((__nonnull__))
  91. { return do_deallocate(__p, __bytes, __alignment); }
  92. bool
  93. is_equal(const memory_resource& __other) const noexcept
  94. { return do_is_equal(__other); }
  95. private:
  96. virtual void*
  97. do_allocate(size_t __bytes, size_t __alignment) = 0;
  98. virtual void
  99. do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0;
  100. virtual bool
  101. do_is_equal(const memory_resource& __other) const noexcept = 0;
  102. };
  103. inline bool
  104. operator==(const memory_resource& __a, const memory_resource& __b) noexcept
  105. { return &__a == &__b || __a.is_equal(__b); }
  106. #if __cpp_impl_three_way_comparison < 201907L
  107. inline bool
  108. operator!=(const memory_resource& __a, const memory_resource& __b) noexcept
  109. { return !(__a == __b); }
  110. #endif
  111. // C++17 23.12.3 Class template polymorphic_allocator
  112. template<typename _Tp>
  113. class polymorphic_allocator
  114. {
  115. // _GLIBCXX_RESOLVE_LIB_DEFECTS
  116. // 2975. Missing case for pair construction in polymorphic allocators
  117. template<typename _Up>
  118. struct __not_pair { using type = void; };
  119. template<typename _Up1, typename _Up2>
  120. struct __not_pair<pair<_Up1, _Up2>> { };
  121. public:
  122. using value_type = _Tp;
  123. polymorphic_allocator() noexcept
  124. : _M_resource(get_default_resource())
  125. { }
  126. polymorphic_allocator(memory_resource* __r) noexcept
  127. __attribute__((__nonnull__))
  128. : _M_resource(__r)
  129. { _GLIBCXX_DEBUG_ASSERT(__r); }
  130. polymorphic_allocator(const polymorphic_allocator& __other) = default;
  131. template<typename _Up>
  132. polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept
  133. : _M_resource(__x.resource())
  134. { }
  135. polymorphic_allocator&
  136. operator=(const polymorphic_allocator&) = delete;
  137. [[nodiscard]]
  138. _Tp*
  139. allocate(size_t __n)
  140. __attribute__((__returns_nonnull__))
  141. {
  142. if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Tp)) < __n)
  143. std::__throw_bad_array_new_length();
  144. return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp),
  145. alignof(_Tp)));
  146. }
  147. void
  148. deallocate(_Tp* __p, size_t __n) noexcept
  149. __attribute__((__nonnull__))
  150. { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
  151. #if __cplusplus > 201703L
  152. [[nodiscard]] void*
  153. allocate_bytes(size_t __nbytes,
  154. size_t __alignment = alignof(max_align_t))
  155. { return _M_resource->allocate(__nbytes, __alignment); }
  156. void
  157. deallocate_bytes(void* __p, size_t __nbytes,
  158. size_t __alignment = alignof(max_align_t))
  159. { _M_resource->deallocate(__p, __nbytes, __alignment); }
  160. template<typename _Up>
  161. [[nodiscard]] _Up*
  162. allocate_object(size_t __n = 1)
  163. {
  164. if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Up)) < __n)
  165. std::__throw_bad_array_new_length();
  166. return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up),
  167. alignof(_Up)));
  168. }
  169. template<typename _Up>
  170. void
  171. deallocate_object(_Up* __p, size_t __n = 1)
  172. { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); }
  173. template<typename _Up, typename... _CtorArgs>
  174. [[nodiscard]] _Up*
  175. new_object(_CtorArgs&&... __ctor_args)
  176. {
  177. _Up* __p = allocate_object<_Up>();
  178. __try
  179. {
  180. construct(__p, std::forward<_CtorArgs>(__ctor_args)...);
  181. }
  182. __catch (...)
  183. {
  184. deallocate_object(__p);
  185. __throw_exception_again;
  186. }
  187. return __p;
  188. }
  189. template<typename _Up>
  190. void
  191. delete_object(_Up* __p)
  192. {
  193. destroy(__p);
  194. deallocate_object(__p);
  195. }
  196. #endif // C++2a
  197. #if ! __cpp_lib_make_obj_using_allocator
  198. template<typename _Tp1, typename... _Args>
  199. __attribute__((__nonnull__))
  200. typename __not_pair<_Tp1>::type
  201. construct(_Tp1* __p, _Args&&... __args)
  202. {
  203. // _GLIBCXX_RESOLVE_LIB_DEFECTS
  204. // 2969. polymorphic_allocator::construct() shouldn't pass resource()
  205. using __use_tag
  206. = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>;
  207. if constexpr (is_base_of_v<__uses_alloc0, __use_tag>)
  208. ::new(__p) _Tp1(std::forward<_Args>(__args)...);
  209. else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>)
  210. ::new(__p) _Tp1(allocator_arg, *this,
  211. std::forward<_Args>(__args)...);
  212. else
  213. ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this);
  214. }
  215. template<typename _Tp1, typename _Tp2,
  216. typename... _Args1, typename... _Args2>
  217. __attribute__((__nonnull__))
  218. void
  219. construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t,
  220. tuple<_Args1...> __x, tuple<_Args2...> __y)
  221. {
  222. auto __x_tag =
  223. __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this);
  224. auto __y_tag =
  225. __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this);
  226. index_sequence_for<_Args1...> __x_i;
  227. index_sequence_for<_Args2...> __y_i;
  228. ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct,
  229. _S_construct_p(__x_tag, __x_i, __x),
  230. _S_construct_p(__y_tag, __y_i, __y));
  231. }
  232. template<typename _Tp1, typename _Tp2>
  233. __attribute__((__nonnull__))
  234. void
  235. construct(pair<_Tp1, _Tp2>* __p)
  236. { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
  237. template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
  238. __attribute__((__nonnull__))
  239. void
  240. construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y)
  241. {
  242. this->construct(__p, piecewise_construct,
  243. std::forward_as_tuple(std::forward<_Up>(__x)),
  244. std::forward_as_tuple(std::forward<_Vp>(__y)));
  245. }
  246. template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
  247. __attribute__((__nonnull__))
  248. void
  249. construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr)
  250. {
  251. this->construct(__p, piecewise_construct,
  252. std::forward_as_tuple(__pr.first),
  253. std::forward_as_tuple(__pr.second));
  254. }
  255. template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
  256. __attribute__((__nonnull__))
  257. void
  258. construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr)
  259. {
  260. this->construct(__p, piecewise_construct,
  261. std::forward_as_tuple(std::forward<_Up>(__pr.first)),
  262. std::forward_as_tuple(std::forward<_Vp>(__pr.second)));
  263. }
  264. #else // make_obj_using_allocator
  265. template<typename _Tp1, typename... _Args>
  266. __attribute__((__nonnull__))
  267. void
  268. construct(_Tp1* __p, _Args&&... __args)
  269. {
  270. std::uninitialized_construct_using_allocator(__p, *this,
  271. std::forward<_Args>(__args)...);
  272. }
  273. #endif
  274. template<typename _Up>
  275. __attribute__((__nonnull__))
  276. void
  277. destroy(_Up* __p)
  278. { __p->~_Up(); }
  279. polymorphic_allocator
  280. select_on_container_copy_construction() const noexcept
  281. { return polymorphic_allocator(); }
  282. memory_resource*
  283. resource() const noexcept
  284. __attribute__((__returns_nonnull__))
  285. { return _M_resource; }
  286. private:
  287. using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
  288. using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
  289. #if ! __cpp_lib_make_obj_using_allocator
  290. template<typename _Ind, typename... _Args>
  291. static tuple<_Args&&...>
  292. _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
  293. { return std::move(__t); }
  294. template<size_t... _Ind, typename... _Args>
  295. static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...>
  296. _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>,
  297. tuple<_Args...>& __t)
  298. {
  299. return {
  300. allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))...
  301. };
  302. }
  303. template<size_t... _Ind, typename... _Args>
  304. static tuple<_Args&&..., polymorphic_allocator>
  305. _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>,
  306. tuple<_Args...>& __t)
  307. { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; }
  308. #endif
  309. memory_resource* _M_resource;
  310. };
  311. template<typename _Tp1, typename _Tp2>
  312. inline bool
  313. operator==(const polymorphic_allocator<_Tp1>& __a,
  314. const polymorphic_allocator<_Tp2>& __b) noexcept
  315. { return *__a.resource() == *__b.resource(); }
  316. #if __cpp_impl_three_way_comparison < 201907L
  317. template<typename _Tp1, typename _Tp2>
  318. inline bool
  319. operator!=(const polymorphic_allocator<_Tp1>& __a,
  320. const polymorphic_allocator<_Tp2>& __b) noexcept
  321. { return !(__a == __b); }
  322. #endif
  323. /// Parameters for tuning a pool resource's behaviour.
  324. struct pool_options
  325. {
  326. /** @brief Upper limit on number of blocks in a chunk.
  327. *
  328. * A lower value prevents allocating huge chunks that could remain mostly
  329. * unused, but means pools will need to replenished more frequently.
  330. */
  331. size_t max_blocks_per_chunk = 0;
  332. /* @brief Largest block size (in bytes) that should be served from pools.
  333. *
  334. * Larger allocations will be served directly by the upstream resource,
  335. * not from one of the pools managed by the pool resource.
  336. */
  337. size_t largest_required_pool_block = 0;
  338. };
  339. // Common implementation details for un-/synchronized pool resources.
  340. class __pool_resource
  341. {
  342. friend class synchronized_pool_resource;
  343. friend class unsynchronized_pool_resource;
  344. __pool_resource(const pool_options& __opts, memory_resource* __upstream);
  345. ~__pool_resource();
  346. __pool_resource(const __pool_resource&) = delete;
  347. __pool_resource& operator=(const __pool_resource&) = delete;
  348. // Allocate a large unpooled block.
  349. void*
  350. allocate(size_t __bytes, size_t __alignment);
  351. // Deallocate a large unpooled block.
  352. void
  353. deallocate(void* __p, size_t __bytes, size_t __alignment);
  354. // Deallocate unpooled memory.
  355. void release() noexcept;
  356. memory_resource* resource() const noexcept
  357. { return _M_unpooled.get_allocator().resource(); }
  358. struct _Pool;
  359. _Pool* _M_alloc_pools();
  360. const pool_options _M_opts;
  361. struct _BigBlock;
  362. // Collection of blocks too big for any pool, sorted by address.
  363. // This also stores the only copy of the upstream memory resource pointer.
  364. _GLIBCXX_STD_C::pmr::vector<_BigBlock> _M_unpooled;
  365. const int _M_npools;
  366. };
  367. #ifdef _GLIBCXX_HAS_GTHREADS
  368. /// A thread-safe memory resource that manages pools of fixed-size blocks.
  369. class synchronized_pool_resource : public memory_resource
  370. {
  371. public:
  372. synchronized_pool_resource(const pool_options& __opts,
  373. memory_resource* __upstream)
  374. __attribute__((__nonnull__));
  375. synchronized_pool_resource()
  376. : synchronized_pool_resource(pool_options(), get_default_resource())
  377. { }
  378. explicit
  379. synchronized_pool_resource(memory_resource* __upstream)
  380. __attribute__((__nonnull__))
  381. : synchronized_pool_resource(pool_options(), __upstream)
  382. { }
  383. explicit
  384. synchronized_pool_resource(const pool_options& __opts)
  385. : synchronized_pool_resource(__opts, get_default_resource()) { }
  386. synchronized_pool_resource(const synchronized_pool_resource&) = delete;
  387. virtual ~synchronized_pool_resource();
  388. synchronized_pool_resource&
  389. operator=(const synchronized_pool_resource&) = delete;
  390. void release();
  391. memory_resource*
  392. upstream_resource() const noexcept
  393. __attribute__((__returns_nonnull__))
  394. { return _M_impl.resource(); }
  395. pool_options options() const noexcept { return _M_impl._M_opts; }
  396. protected:
  397. void*
  398. do_allocate(size_t __bytes, size_t __alignment) override;
  399. void
  400. do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
  401. bool
  402. do_is_equal(const memory_resource& __other) const noexcept override
  403. { return this == &__other; }
  404. public:
  405. // Thread-specific pools (only public for access by implementation details)
  406. struct _TPools;
  407. private:
  408. _TPools* _M_alloc_tpools(lock_guard<shared_mutex>&);
  409. _TPools* _M_alloc_shared_tpools(lock_guard<shared_mutex>&);
  410. auto _M_thread_specific_pools() noexcept;
  411. __pool_resource _M_impl;
  412. __gthread_key_t _M_key;
  413. // Linked list of thread-specific pools. All threads share _M_tpools[0].
  414. _TPools* _M_tpools = nullptr;
  415. mutable shared_mutex _M_mx;
  416. };
  417. #endif
  418. /// A non-thread-safe memory resource that manages pools of fixed-size blocks.
  419. class unsynchronized_pool_resource : public memory_resource
  420. {
  421. public:
  422. [[__gnu__::__nonnull__]]
  423. unsynchronized_pool_resource(const pool_options& __opts,
  424. memory_resource* __upstream);
  425. unsynchronized_pool_resource()
  426. : unsynchronized_pool_resource(pool_options(), get_default_resource())
  427. { }
  428. [[__gnu__::__nonnull__]]
  429. explicit
  430. unsynchronized_pool_resource(memory_resource* __upstream)
  431. : unsynchronized_pool_resource(pool_options(), __upstream)
  432. { }
  433. explicit
  434. unsynchronized_pool_resource(const pool_options& __opts)
  435. : unsynchronized_pool_resource(__opts, get_default_resource()) { }
  436. unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
  437. virtual ~unsynchronized_pool_resource();
  438. unsynchronized_pool_resource&
  439. operator=(const unsynchronized_pool_resource&) = delete;
  440. void release();
  441. [[__gnu__::__returns_nonnull__]]
  442. memory_resource*
  443. upstream_resource() const noexcept
  444. { return _M_impl.resource(); }
  445. pool_options options() const noexcept { return _M_impl._M_opts; }
  446. protected:
  447. void*
  448. do_allocate(size_t __bytes, size_t __alignment) override;
  449. void
  450. do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
  451. bool
  452. do_is_equal(const memory_resource& __other) const noexcept override
  453. { return this == &__other; }
  454. private:
  455. using _Pool = __pool_resource::_Pool;
  456. auto _M_find_pool(size_t) noexcept;
  457. __pool_resource _M_impl;
  458. _Pool* _M_pools = nullptr;
  459. };
  460. class monotonic_buffer_resource : public memory_resource
  461. {
  462. public:
  463. explicit
  464. monotonic_buffer_resource(memory_resource* __upstream) noexcept
  465. __attribute__((__nonnull__))
  466. : _M_upstream(__upstream)
  467. { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); }
  468. monotonic_buffer_resource(size_t __initial_size,
  469. memory_resource* __upstream) noexcept
  470. __attribute__((__nonnull__))
  471. : _M_next_bufsiz(__initial_size),
  472. _M_upstream(__upstream)
  473. {
  474. _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
  475. _GLIBCXX_DEBUG_ASSERT(__initial_size > 0);
  476. }
  477. monotonic_buffer_resource(void* __buffer, size_t __buffer_size,
  478. memory_resource* __upstream) noexcept
  479. __attribute__((__nonnull__(4)))
  480. : _M_current_buf(__buffer), _M_avail(__buffer_size),
  481. _M_next_bufsiz(_S_next_bufsize(__buffer_size)),
  482. _M_upstream(__upstream),
  483. _M_orig_buf(__buffer), _M_orig_size(__buffer_size)
  484. {
  485. _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
  486. _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0);
  487. }
  488. monotonic_buffer_resource() noexcept
  489. : monotonic_buffer_resource(get_default_resource())
  490. { }
  491. explicit
  492. monotonic_buffer_resource(size_t __initial_size) noexcept
  493. : monotonic_buffer_resource(__initial_size, get_default_resource())
  494. { }
  495. monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept
  496. : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource())
  497. { }
  498. monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
  499. virtual ~monotonic_buffer_resource(); // key function
  500. monotonic_buffer_resource&
  501. operator=(const monotonic_buffer_resource&) = delete;
  502. void
  503. release() noexcept
  504. {
  505. if (_M_head)
  506. _M_release_buffers();
  507. // reset to initial state at contruction:
  508. if ((_M_current_buf = _M_orig_buf))
  509. {
  510. _M_avail = _M_orig_size;
  511. _M_next_bufsiz = _S_next_bufsize(_M_orig_size);
  512. }
  513. else
  514. {
  515. _M_avail = 0;
  516. _M_next_bufsiz = _M_orig_size;
  517. }
  518. }
  519. memory_resource*
  520. upstream_resource() const noexcept
  521. __attribute__((__returns_nonnull__))
  522. { return _M_upstream; }
  523. protected:
  524. void*
  525. do_allocate(size_t __bytes, size_t __alignment) override
  526. {
  527. if (__builtin_expect(__bytes == 0, false))
  528. __bytes = 1; // Ensures we don't return the same pointer twice.
  529. void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail);
  530. if (__builtin_expect(__p == nullptr, false))
  531. {
  532. _M_new_buffer(__bytes, __alignment);
  533. __p = _M_current_buf;
  534. }
  535. _M_current_buf = (char*)_M_current_buf + __bytes;
  536. _M_avail -= __bytes;
  537. return __p;
  538. }
  539. void
  540. do_deallocate(void*, size_t, size_t) override
  541. { }
  542. bool
  543. do_is_equal(const memory_resource& __other) const noexcept override
  544. { return this == &__other; }
  545. private:
  546. // Update _M_current_buf and _M_avail to refer to a new buffer with
  547. // at least the specified size and alignment, allocated from upstream.
  548. void
  549. _M_new_buffer(size_t __bytes, size_t __alignment);
  550. // Deallocate all buffers obtained from upstream.
  551. void
  552. _M_release_buffers() noexcept;
  553. static size_t
  554. _S_next_bufsize(size_t __buffer_size) noexcept
  555. {
  556. if (__builtin_expect(__buffer_size == 0, false))
  557. __buffer_size = 1;
  558. return __buffer_size * _S_growth_factor;
  559. }
  560. static constexpr size_t _S_init_bufsize = 128 * sizeof(void*);
  561. static constexpr float _S_growth_factor = 1.5;
  562. void* _M_current_buf = nullptr;
  563. size_t _M_avail = 0;
  564. size_t _M_next_bufsiz = _S_init_bufsize;
  565. // Initial values set at construction and reused by release():
  566. memory_resource* const _M_upstream;
  567. void* const _M_orig_buf = nullptr;
  568. size_t const _M_orig_size = _M_next_bufsiz;
  569. class _Chunk;
  570. _Chunk* _M_head = nullptr;
  571. };
  572. } // namespace pmr
  573. _GLIBCXX_END_NAMESPACE_VERSION
  574. } // namespace std
  575. #endif // C++17
  576. #endif // _GLIBCXX_MEMORY_RESOURCE