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