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