1// <memory_resource> -*- C++ -*-
3// Copyright (C) 2018-2022 Free Software Foundation, Inc.
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
25/** @file include/memory_resource
26 * This is a Standard C++ Library header.
29#ifndef _GLIBCXX_MEMORY_RESOURCE
30#define _GLIBCXX_MEMORY_RESOURCE 1
32#pragma GCC system_header
34#if __cplusplus >= 201703L
37#include <vector> // vector
38#include <cstddef> // size_t, max_align_t, byte
39#include <shared_mutex> // shared_mutex
40#include <bits/align.h> // align
41#include <bits/functexcept.h> // __throw_bad_array_new_length
42#include <bits/uses_allocator.h> // allocator_arg_t, __use_alloc
43#include <bits/uses_allocator_args.h> // uninitialized_construct_using_alloc
44#include <ext/numeric_traits.h>
45#include <debug/assertions.h>
47#if ! __cpp_lib_make_obj_using_allocator
48# include <bits/utility.h> // index_sequence
49# include <tuple> // tuple, forward_as_tuple
52namespace std _GLIBCXX_VISIBILITY(default)
54_GLIBCXX_BEGIN_NAMESPACE_VERSION
57#ifdef _GLIBCXX_HAS_GTHREADS
58 // Header and all contents are present.
59# define __cpp_lib_memory_resource 201603L
61 // The pmr::synchronized_pool_resource type is missing.
62# define __cpp_lib_memory_resource 1
65 class memory_resource;
67#if __cplusplus == 201703L
68 template<typename _Tp>
69 class polymorphic_allocator;
71# define __cpp_lib_polymorphic_allocator 201902L
72 template<typename _Tp = std::byte>
73 class polymorphic_allocator;
76 // Global memory resources
78 /// A pmr::memory_resource that uses `new` to allocate memory
79 [[nodiscard, __gnu__::__returns_nonnull__, __gnu__::__const__]]
81 new_delete_resource() noexcept;
83 /// A pmr::memory_resource that always throws `bad_alloc`
84 [[nodiscard, __gnu__::__returns_nonnull__, __gnu__::__const__]]
86 null_memory_resource() noexcept;
88 /// Replace the default memory resource pointer
89 [[__gnu__::__returns_nonnull__]]
91 set_default_resource(memory_resource* __r) noexcept;
93 /// Get the current default memory resource pointer
94 [[__gnu__::__returns_nonnull__]]
96 get_default_resource() noexcept;
98 // Pool resource classes
100#ifdef _GLIBCXX_HAS_GTHREADS
101 class synchronized_pool_resource;
103 class unsynchronized_pool_resource;
104 class monotonic_buffer_resource;
106 /// Class memory_resource
107 class memory_resource
109 static constexpr size_t _S_max_align = alignof(max_align_t);
112 memory_resource() = default;
113 memory_resource(const memory_resource&) = default;
114 virtual ~memory_resource(); // key function
116 memory_resource& operator=(const memory_resource&) = default;
120 allocate(size_t __bytes, size_t __alignment = _S_max_align)
121 __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3)))
122 { return ::operator new(__bytes, do_allocate(__bytes, __alignment)); }
125 deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
126 __attribute__((__nonnull__))
127 { return do_deallocate(__p, __bytes, __alignment); }
131 is_equal(const memory_resource& __other) const noexcept
132 { return do_is_equal(__other); }
136 do_allocate(size_t __bytes, size_t __alignment) = 0;
139 do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0;
142 do_is_equal(const memory_resource& __other) const noexcept = 0;
147 operator==(const memory_resource& __a, const memory_resource& __b) noexcept
148 { return &__a == &__b || __a.is_equal(__b); }
150#if __cpp_impl_three_way_comparison < 201907L
153 operator!=(const memory_resource& __a, const memory_resource& __b) noexcept
154 { return !(__a == __b); }
157 // C++17 23.12.3 Class template polymorphic_allocator
158 template<typename _Tp>
159 class polymorphic_allocator
161 // _GLIBCXX_RESOLVE_LIB_DEFECTS
162 // 2975. Missing case for pair construction in polymorphic allocators
163 template<typename _Up>
164 struct __not_pair { using type = void; };
166 template<typename _Up1, typename _Up2>
167 struct __not_pair<pair<_Up1, _Up2>> { };
170 using value_type = _Tp;
172 polymorphic_allocator() noexcept
173 : _M_resource(get_default_resource())
176 polymorphic_allocator(memory_resource* __r) noexcept
177 __attribute__((__nonnull__))
179 { _GLIBCXX_DEBUG_ASSERT(__r); }
181 polymorphic_allocator(const polymorphic_allocator& __other) = default;
183 template<typename _Up>
184 polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept
185 : _M_resource(__x.resource())
188 polymorphic_allocator&
189 operator=(const polymorphic_allocator&) = delete;
194 __attribute__((__returns_nonnull__))
196 if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Tp)) < __n)
197 std::__throw_bad_array_new_length();
198 return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp),
203 deallocate(_Tp* __p, size_t __n) noexcept
204 __attribute__((__nonnull__))
205 { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
207#if __cplusplus > 201703L
209 allocate_bytes(size_t __nbytes,
210 size_t __alignment = alignof(max_align_t))
211 { return _M_resource->allocate(__nbytes, __alignment); }
214 deallocate_bytes(void* __p, size_t __nbytes,
215 size_t __alignment = alignof(max_align_t))
216 { _M_resource->deallocate(__p, __nbytes, __alignment); }
218 template<typename _Up>
220 allocate_object(size_t __n = 1)
222 if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Up)) < __n)
223 std::__throw_bad_array_new_length();
224 return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up),
228 template<typename _Up>
230 deallocate_object(_Up* __p, size_t __n = 1)
231 { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); }
233 template<typename _Up, typename... _CtorArgs>
235 new_object(_CtorArgs&&... __ctor_args)
237 _Up* __p = allocate_object<_Up>();
240 construct(__p, std::forward<_CtorArgs>(__ctor_args)...);
244 deallocate_object(__p);
245 __throw_exception_again;
250 template<typename _Up>
252 delete_object(_Up* __p)
255 deallocate_object(__p);
259#if ! __cpp_lib_make_obj_using_allocator
260 template<typename _Tp1, typename... _Args>
261 __attribute__((__nonnull__))
262 typename __not_pair<_Tp1>::type
263 construct(_Tp1* __p, _Args&&... __args)
265 // _GLIBCXX_RESOLVE_LIB_DEFECTS
266 // 2969. polymorphic_allocator::construct() shouldn't pass resource()
268 = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>;
269 if constexpr (is_base_of_v<__uses_alloc0, __use_tag>)
270 ::new(__p) _Tp1(std::forward<_Args>(__args)...);
271 else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>)
272 ::new(__p) _Tp1(allocator_arg, *this,
273 std::forward<_Args>(__args)...);
275 ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this);
278 template<typename _Tp1, typename _Tp2,
279 typename... _Args1, typename... _Args2>
280 __attribute__((__nonnull__))
282 construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t,
283 tuple<_Args1...> __x, tuple<_Args2...> __y)
286 __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this);
288 __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this);
289 index_sequence_for<_Args1...> __x_i;
290 index_sequence_for<_Args2...> __y_i;
292 ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct,
293 _S_construct_p(__x_tag, __x_i, __x),
294 _S_construct_p(__y_tag, __y_i, __y));
297 template<typename _Tp1, typename _Tp2>
298 __attribute__((__nonnull__))
300 construct(pair<_Tp1, _Tp2>* __p)
301 { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
303 template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
304 __attribute__((__nonnull__))
306 construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y)
308 this->construct(__p, piecewise_construct,
309 std::forward_as_tuple(std::forward<_Up>(__x)),
310 std::forward_as_tuple(std::forward<_Vp>(__y)));
313 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
314 __attribute__((__nonnull__))
316 construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr)
318 this->construct(__p, piecewise_construct,
319 std::forward_as_tuple(__pr.first),
320 std::forward_as_tuple(__pr.second));
323 template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
324 __attribute__((__nonnull__))
326 construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr)
328 this->construct(__p, piecewise_construct,
329 std::forward_as_tuple(std::forward<_Up>(__pr.first)),
330 std::forward_as_tuple(std::forward<_Vp>(__pr.second)));
332#else // make_obj_using_allocator
333 template<typename _Tp1, typename... _Args>
334 __attribute__((__nonnull__))
336 construct(_Tp1* __p, _Args&&... __args)
338 std::uninitialized_construct_using_allocator(__p, *this,
339 std::forward<_Args>(__args)...);
343 template<typename _Up>
344 _GLIBCXX20_DEPRECATED_SUGGEST("allocator_traits::destroy")
345 __attribute__((__nonnull__))
350 polymorphic_allocator
351 select_on_container_copy_construction() const noexcept
352 { return polymorphic_allocator(); }
355 resource() const noexcept
356 __attribute__((__returns_nonnull__))
357 { return _M_resource; }
359 // _GLIBCXX_RESOLVE_LIB_DEFECTS
360 // 3683. operator== for polymorphic_allocator cannot deduce template arg
363 operator==(const polymorphic_allocator& __a,
364 const polymorphic_allocator& __b) noexcept
365 { return *__a.resource() == *__b.resource(); }
367#if __cpp_impl_three_way_comparison < 201907L
370 operator!=(const polymorphic_allocator& __a,
371 const polymorphic_allocator& __b) noexcept
372 { return !(__a == __b); }
376#if ! __cpp_lib_make_obj_using_allocator
377 using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
378 using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
380 template<typename _Ind, typename... _Args>
381 static tuple<_Args&&...>
382 _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
383 { return std::move(__t); }
385 template<size_t... _Ind, typename... _Args>
386 static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...>
387 _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>,
388 tuple<_Args...>& __t)
391 allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))...
395 template<size_t... _Ind, typename... _Args>
396 static tuple<_Args&&..., polymorphic_allocator>
397 _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>,
398 tuple<_Args...>& __t)
399 { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; }
402 memory_resource* _M_resource;
405 template<typename _Tp1, typename _Tp2>
408 operator==(const polymorphic_allocator<_Tp1>& __a,
409 const polymorphic_allocator<_Tp2>& __b) noexcept
410 { return *__a.resource() == *__b.resource(); }
412#if __cpp_impl_three_way_comparison < 201907L
413 template<typename _Tp1, typename _Tp2>
416 operator!=(const polymorphic_allocator<_Tp1>& __a,
417 const polymorphic_allocator<_Tp2>& __b) noexcept
418 { return !(__a == __b); }
423 /// Partial specialization for std::pmr::polymorphic_allocator
424 template<typename _Tp>
425 struct allocator_traits<pmr::polymorphic_allocator<_Tp>>
427 /// The allocator type
428 using allocator_type = pmr::polymorphic_allocator<_Tp>;
430 /// The allocated type
431 using value_type = _Tp;
433 /// The allocator's pointer type.
434 using pointer = _Tp*;
436 /// The allocator's const pointer type.
437 using const_pointer = const _Tp*;
439 /// The allocator's void pointer type.
440 using void_pointer = void*;
442 /// The allocator's const void pointer type.
443 using const_void_pointer = const void*;
445 /// The allocator's difference type
446 using difference_type = std::ptrdiff_t;
448 /// The allocator's size type
449 using size_type = std::size_t;
452 * A `polymorphic_allocator` does not propagate when a
453 * container is copied, moved, or swapped.
455 using propagate_on_container_copy_assignment = false_type;
456 using propagate_on_container_move_assignment = false_type;
457 using propagate_on_container_swap = false_type;
459 static allocator_type
460 select_on_container_copy_construction(const allocator_type&) noexcept
461 { return allocator_type(); }
464 /// Whether all instances of the allocator type compare equal.
465 using is_always_equal = false_type;
467 template<typename _Up>
468 using rebind_alloc = pmr::polymorphic_allocator<_Up>;
470 template<typename _Up>
471 using rebind_traits = allocator_traits<pmr::polymorphic_allocator<_Up>>;
474 * @brief Allocate memory.
475 * @param __a An allocator.
476 * @param __n The number of objects to allocate space for.
478 * Calls `a.allocate(n)`.
480 [[nodiscard]] static pointer
481 allocate(allocator_type& __a, size_type __n)
482 { return __a.allocate(__n); }
485 * @brief Allocate memory.
486 * @param __a An allocator.
487 * @param __n The number of objects to allocate space for.
488 * @return Memory of suitable size and alignment for `n` objects
489 * of type `value_type`.
491 * The third parameter is ignored..
493 * Returns `a.allocate(n)`.
495 [[nodiscard]] static pointer
496 allocate(allocator_type& __a, size_type __n, const_void_pointer)
497 { return __a.allocate(__n); }
500 * @brief Deallocate memory.
501 * @param __a An allocator.
502 * @param __p Pointer to the memory to deallocate.
503 * @param __n The number of objects space was allocated for.
505 * Calls `a.deallocate(p, n)`.
508 deallocate(allocator_type& __a, pointer __p, size_type __n)
509 { __a.deallocate(__p, __n); }
512 * @brief Construct an object of type `_Up`
513 * @param __a An allocator.
514 * @param __p Pointer to memory of suitable size and alignment for
515 * an object of type `_Up`.
516 * @param __args Constructor arguments.
518 * Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
519 * in C++11, C++14 and C++17. Changed in C++20 to call
520 * `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
522 template<typename _Up, typename... _Args>
524 construct(allocator_type& __a, _Up* __p, _Args&&... __args)
525 { __a.construct(__p, std::forward<_Args>(__args)...); }
528 * @brief Destroy an object of type `_Up`
529 * @param __a An allocator.
530 * @param __p Pointer to the object to destroy
534 template<typename _Up>
535 static _GLIBCXX20_CONSTEXPR void
536 destroy(allocator_type&, _Up* __p)
537 noexcept(is_nothrow_destructible<_Up>::value)
541 * @brief The maximum supported allocation size
542 * @return `numeric_limits<size_t>::max() / sizeof(value_type)`
544 static _GLIBCXX20_CONSTEXPR size_type
545 max_size(const allocator_type&) noexcept
546 { return size_t(-1) / sizeof(value_type); }
551 /// Parameters for tuning a pool resource's behaviour.
554 /** @brief Upper limit on number of blocks in a chunk.
556 * A lower value prevents allocating huge chunks that could remain mostly
557 * unused, but means pools will need to replenished more frequently.
559 size_t max_blocks_per_chunk = 0;
561 /* @brief Largest block size (in bytes) that should be served from pools.
563 * Larger allocations will be served directly by the upstream resource,
564 * not from one of the pools managed by the pool resource.
566 size_t largest_required_pool_block = 0;
569 // Common implementation details for un-/synchronized pool resources.
570 class __pool_resource
572 friend class synchronized_pool_resource;
573 friend class unsynchronized_pool_resource;
575 __pool_resource(const pool_options& __opts, memory_resource* __upstream);
579 __pool_resource(const __pool_resource&) = delete;
580 __pool_resource& operator=(const __pool_resource&) = delete;
582 // Allocate a large unpooled block.
584 allocate(size_t __bytes, size_t __alignment);
586 // Deallocate a large unpooled block.
588 deallocate(void* __p, size_t __bytes, size_t __alignment);
591 // Deallocate unpooled memory.
592 void release() noexcept;
594 memory_resource* resource() const noexcept
595 { return _M_unpooled.get_allocator().resource(); }
599 _Pool* _M_alloc_pools();
601 const pool_options _M_opts;
604 // Collection of blocks too big for any pool, sorted by address.
605 // This also stores the only copy of the upstream memory resource pointer.
606 _GLIBCXX_STD_C::pmr::vector<_BigBlock> _M_unpooled;
611#ifdef _GLIBCXX_HAS_GTHREADS
612 /// A thread-safe memory resource that manages pools of fixed-size blocks.
613 class synchronized_pool_resource : public memory_resource
616 synchronized_pool_resource(const pool_options& __opts,
617 memory_resource* __upstream)
618 __attribute__((__nonnull__));
620 synchronized_pool_resource()
621 : synchronized_pool_resource(pool_options(), get_default_resource())
625 synchronized_pool_resource(memory_resource* __upstream)
626 __attribute__((__nonnull__))
627 : synchronized_pool_resource(pool_options(), __upstream)
631 synchronized_pool_resource(const pool_options& __opts)
632 : synchronized_pool_resource(__opts, get_default_resource()) { }
634 synchronized_pool_resource(const synchronized_pool_resource&) = delete;
636 virtual ~synchronized_pool_resource();
638 synchronized_pool_resource&
639 operator=(const synchronized_pool_resource&) = delete;
644 upstream_resource() const noexcept
645 __attribute__((__returns_nonnull__))
646 { return _M_impl.resource(); }
648 pool_options options() const noexcept { return _M_impl._M_opts; }
652 do_allocate(size_t __bytes, size_t __alignment) override;
655 do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
658 do_is_equal(const memory_resource& __other) const noexcept override
659 { return this == &__other; }
662 // Thread-specific pools (only public for access by implementation details)
666 _TPools* _M_alloc_tpools(lock_guard<shared_mutex>&);
667 _TPools* _M_alloc_shared_tpools(lock_guard<shared_mutex>&);
668 auto _M_thread_specific_pools() noexcept;
670 __pool_resource _M_impl;
671 __gthread_key_t _M_key;
672 // Linked list of thread-specific pools. All threads share _M_tpools[0].
673 _TPools* _M_tpools = nullptr;
674 mutable shared_mutex _M_mx;
678 /// A non-thread-safe memory resource that manages pools of fixed-size blocks.
679 class unsynchronized_pool_resource : public memory_resource
682 [[__gnu__::__nonnull__]]
683 unsynchronized_pool_resource(const pool_options& __opts,
684 memory_resource* __upstream);
686 unsynchronized_pool_resource()
687 : unsynchronized_pool_resource(pool_options(), get_default_resource())
690 [[__gnu__::__nonnull__]]
692 unsynchronized_pool_resource(memory_resource* __upstream)
693 : unsynchronized_pool_resource(pool_options(), __upstream)
697 unsynchronized_pool_resource(const pool_options& __opts)
698 : unsynchronized_pool_resource(__opts, get_default_resource()) { }
700 unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
702 virtual ~unsynchronized_pool_resource();
704 unsynchronized_pool_resource&
705 operator=(const unsynchronized_pool_resource&) = delete;
709 [[__gnu__::__returns_nonnull__]]
711 upstream_resource() const noexcept
712 { return _M_impl.resource(); }
714 pool_options options() const noexcept { return _M_impl._M_opts; }
718 do_allocate(size_t __bytes, size_t __alignment) override;
721 do_deallocate(void* __p, size_t __bytes, size_t __alignment) override;
724 do_is_equal(const memory_resource& __other) const noexcept override
725 { return this == &__other; }
728 using _Pool = __pool_resource::_Pool;
730 auto _M_find_pool(size_t) noexcept;
732 __pool_resource _M_impl;
733 _Pool* _M_pools = nullptr;
736 class monotonic_buffer_resource : public memory_resource
740 monotonic_buffer_resource(memory_resource* __upstream) noexcept
741 __attribute__((__nonnull__))
742 : _M_upstream(__upstream)
743 { _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr); }
745 monotonic_buffer_resource(size_t __initial_size,
746 memory_resource* __upstream) noexcept
747 __attribute__((__nonnull__))
748 : _M_next_bufsiz(__initial_size),
749 _M_upstream(__upstream)
751 _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
752 _GLIBCXX_DEBUG_ASSERT(__initial_size > 0);
755 monotonic_buffer_resource(void* __buffer, size_t __buffer_size,
756 memory_resource* __upstream) noexcept
757 __attribute__((__nonnull__(4)))
758 : _M_current_buf(__buffer), _M_avail(__buffer_size),
759 _M_next_bufsiz(_S_next_bufsize(__buffer_size)),
760 _M_upstream(__upstream),
761 _M_orig_buf(__buffer), _M_orig_size(__buffer_size)
763 _GLIBCXX_DEBUG_ASSERT(__upstream != nullptr);
764 _GLIBCXX_DEBUG_ASSERT(__buffer != nullptr || __buffer_size == 0);
767 monotonic_buffer_resource() noexcept
768 : monotonic_buffer_resource(get_default_resource())
772 monotonic_buffer_resource(size_t __initial_size) noexcept
773 : monotonic_buffer_resource(__initial_size, get_default_resource())
776 monotonic_buffer_resource(void* __buffer, size_t __buffer_size) noexcept
777 : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource())
780 monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
782 virtual ~monotonic_buffer_resource(); // key function
784 monotonic_buffer_resource&
785 operator=(const monotonic_buffer_resource&) = delete;
791 _M_release_buffers();
793 // reset to initial state at contruction:
794 if ((_M_current_buf = _M_orig_buf))
796 _M_avail = _M_orig_size;
797 _M_next_bufsiz = _S_next_bufsize(_M_orig_size);
802 _M_next_bufsiz = _M_orig_size;
807 upstream_resource() const noexcept
808 __attribute__((__returns_nonnull__))
809 { return _M_upstream; }
813 do_allocate(size_t __bytes, size_t __alignment) override
815 if (__builtin_expect(__bytes == 0, false))
816 __bytes = 1; // Ensures we don't return the same pointer twice.
818 void* __p = std::align(__alignment, __bytes, _M_current_buf, _M_avail);
819 if (__builtin_expect(__p == nullptr, false))
821 _M_new_buffer(__bytes, __alignment);
822 __p = _M_current_buf;
824 _M_current_buf = (char*)_M_current_buf + __bytes;
830 do_deallocate(void*, size_t, size_t) override
834 do_is_equal(const memory_resource& __other) const noexcept override
835 { return this == &__other; }
838 // Update _M_current_buf and _M_avail to refer to a new buffer with
839 // at least the specified size and alignment, allocated from upstream.
841 _M_new_buffer(size_t __bytes, size_t __alignment);
843 // Deallocate all buffers obtained from upstream.
845 _M_release_buffers() noexcept;
848 _S_next_bufsize(size_t __buffer_size) noexcept
850 if (__builtin_expect(__buffer_size == 0, false))
852 return __buffer_size * _S_growth_factor;
855 static constexpr size_t _S_init_bufsize = 128 * sizeof(void*);
856 static constexpr float _S_growth_factor = 1.5;
858 void* _M_current_buf = nullptr;
860 size_t _M_next_bufsiz = _S_init_bufsize;
862 // Initial values set at construction and reused by release():
863 memory_resource* const _M_upstream;
864 void* const _M_orig_buf = nullptr;
865 size_t const _M_orig_size = _M_next_bufsiz;
868 _Chunk* _M_head = nullptr;
872_GLIBCXX_END_NAMESPACE_VERSION
876#endif // _GLIBCXX_MEMORY_RESOURCE