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