libstdc++
memory_resource.h
Go to the documentation of this file.
1// <memory_resource> -*- C++ -*-
2
3// Copyright (C) 2018-2023 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/bits/memory_resource.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{memory_resource}
28 */
29
30#ifndef _GLIBCXX_MEMORY_RESOURCE_H
31#define _GLIBCXX_MEMORY_RESOURCE_H 1
32
33#pragma GCC system_header
34
35#if __cplusplus >= 201703L
36
37#include <new> // operator new(size_t, void*)
38#include <cstddef> // size_t, max_align_t, byte
39#include <bits/functexcept.h> // __throw_bad_array_new_length
40#include <bits/uses_allocator.h> // allocator_arg_t, __use_alloc
41#include <bits/uses_allocator_args.h> // uninitialized_construct_using_alloc
42#include <ext/numeric_traits.h> // __int_traits
43#include <debug/assertions.h>
44
45#if ! __cpp_lib_make_obj_using_allocator
46# include <bits/utility.h> // index_sequence
47# include <tuple> // tuple, forward_as_tuple
48#endif
49
50namespace std _GLIBCXX_VISIBILITY(default)
51{
52_GLIBCXX_BEGIN_NAMESPACE_VERSION
53namespace pmr
54{
55 /// Class memory_resource
57 {
58 static constexpr size_t _S_max_align = alignof(max_align_t);
59
60 public:
61 memory_resource() = default;
62 memory_resource(const memory_resource&) = default;
63 virtual ~memory_resource(); // key function
64
65 memory_resource& operator=(const memory_resource&) = default;
66
67 [[nodiscard]]
68 void*
69 allocate(size_t __bytes, size_t __alignment = _S_max_align)
70 __attribute__((__returns_nonnull__,__alloc_size__(2),__alloc_align__(3)))
71 { return ::operator new(__bytes, do_allocate(__bytes, __alignment)); }
72
73 void
74 deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
75 __attribute__((__nonnull__))
76 { return do_deallocate(__p, __bytes, __alignment); }
77
78 [[nodiscard]]
79 bool
80 is_equal(const memory_resource& __other) const noexcept
81 { return do_is_equal(__other); }
82
83 private:
84 virtual void*
85 do_allocate(size_t __bytes, size_t __alignment) = 0;
86
87 virtual void
88 do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0;
89
90 virtual bool
91 do_is_equal(const memory_resource& __other) const noexcept = 0;
92 };
93
94 [[nodiscard]]
95 inline bool
96 operator==(const memory_resource& __a, const memory_resource& __b) noexcept
97 { return &__a == &__b || __a.is_equal(__b); }
98
99#if __cpp_impl_three_way_comparison < 201907L
100 [[nodiscard]]
101 inline bool
102 operator!=(const memory_resource& __a, const memory_resource& __b) noexcept
103 { return !(__a == __b); }
104#endif
105
106 // C++17 23.12.3 Class template polymorphic_allocator
107 template<typename _Tp>
108 class polymorphic_allocator
109 {
110 // _GLIBCXX_RESOLVE_LIB_DEFECTS
111 // 2975. Missing case for pair construction in polymorphic allocators
112 template<typename _Up>
113 struct __not_pair { using type = void; };
114
115 template<typename _Up1, typename _Up2>
116 struct __not_pair<pair<_Up1, _Up2>> { };
117
118 public:
119 using value_type = _Tp;
120
121 polymorphic_allocator() noexcept
122 {
123 extern memory_resource* get_default_resource() noexcept
124 __attribute__((__returns_nonnull__));
125 _M_resource = get_default_resource();
126 }
127
128 polymorphic_allocator(memory_resource* __r) noexcept
129 __attribute__((__nonnull__))
130 : _M_resource(__r)
131 { _GLIBCXX_DEBUG_ASSERT(__r); }
132
133 polymorphic_allocator(const polymorphic_allocator& __other) = default;
134
135 template<typename _Up>
136 polymorphic_allocator(const polymorphic_allocator<_Up>& __x) noexcept
137 : _M_resource(__x.resource())
138 { }
139
140 polymorphic_allocator&
141 operator=(const polymorphic_allocator&) = delete;
142
143 [[nodiscard]]
144 _Tp*
145 allocate(size_t __n)
146 __attribute__((__returns_nonnull__))
147 {
148 if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Tp)) < __n)
149 std::__throw_bad_array_new_length();
150 return static_cast<_Tp*>(_M_resource->allocate(__n * sizeof(_Tp),
151 alignof(_Tp)));
152 }
153
154 void
155 deallocate(_Tp* __p, size_t __n) noexcept
156 __attribute__((__nonnull__))
157 { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); }
158
159#if __cplusplus > 201703L
160 [[nodiscard]] void*
161 allocate_bytes(size_t __nbytes,
162 size_t __alignment = alignof(max_align_t))
163 { return _M_resource->allocate(__nbytes, __alignment); }
164
165 void
166 deallocate_bytes(void* __p, size_t __nbytes,
167 size_t __alignment = alignof(max_align_t))
168 { _M_resource->deallocate(__p, __nbytes, __alignment); }
169
170 template<typename _Up>
171 [[nodiscard]] _Up*
172 allocate_object(size_t __n = 1)
173 {
174 if ((__gnu_cxx::__int_traits<size_t>::__max / sizeof(_Up)) < __n)
175 std::__throw_bad_array_new_length();
176 return static_cast<_Up*>(allocate_bytes(__n * sizeof(_Up),
177 alignof(_Up)));
178 }
179
180 template<typename _Up>
181 void
182 deallocate_object(_Up* __p, size_t __n = 1)
183 { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); }
184
185 template<typename _Up, typename... _CtorArgs>
186 [[nodiscard]] _Up*
187 new_object(_CtorArgs&&... __ctor_args)
188 {
189 _Up* __p = allocate_object<_Up>();
190 __try
191 {
192 construct(__p, std::forward<_CtorArgs>(__ctor_args)...);
193 }
194 __catch (...)
195 {
196 deallocate_object(__p);
197 __throw_exception_again;
198 }
199 return __p;
200 }
201
202 template<typename _Up>
203 void
204 delete_object(_Up* __p)
205 {
206 __p->~_Up();
207 deallocate_object(__p);
208 }
209#endif // C++2a
210
211#if ! __cpp_lib_make_obj_using_allocator
212 template<typename _Tp1, typename... _Args>
213 __attribute__((__nonnull__))
214 typename __not_pair<_Tp1>::type
215 construct(_Tp1* __p, _Args&&... __args)
216 {
217 // _GLIBCXX_RESOLVE_LIB_DEFECTS
218 // 2969. polymorphic_allocator::construct() shouldn't pass resource()
219 using __use_tag
220 = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>;
221 if constexpr (is_base_of_v<__uses_alloc0, __use_tag>)
222 ::new(__p) _Tp1(std::forward<_Args>(__args)...);
223 else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>)
224 ::new(__p) _Tp1(allocator_arg, *this,
225 std::forward<_Args>(__args)...);
226 else
227 ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this);
228 }
229
230 template<typename _Tp1, typename _Tp2,
231 typename... _Args1, typename... _Args2>
232 __attribute__((__nonnull__))
233 void
234 construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t,
235 tuple<_Args1...> __x, tuple<_Args2...> __y)
236 {
237 auto __x_tag =
238 __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this);
239 auto __y_tag =
240 __use_alloc<_Tp2, polymorphic_allocator, _Args2...>(*this);
241 index_sequence_for<_Args1...> __x_i;
242 index_sequence_for<_Args2...> __y_i;
243
244 ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct,
245 _S_construct_p(__x_tag, __x_i, __x),
246 _S_construct_p(__y_tag, __y_i, __y));
247 }
248
249 template<typename _Tp1, typename _Tp2>
250 __attribute__((__nonnull__))
251 void
252 construct(pair<_Tp1, _Tp2>* __p)
253 { this->construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
254
255 template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
256 __attribute__((__nonnull__))
257 void
258 construct(pair<_Tp1, _Tp2>* __p, _Up&& __x, _Vp&& __y)
259 {
260 this->construct(__p, piecewise_construct,
261 std::forward_as_tuple(std::forward<_Up>(__x)),
262 std::forward_as_tuple(std::forward<_Vp>(__y)));
263 }
264
265 template <typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
266 __attribute__((__nonnull__))
267 void
268 construct(pair<_Tp1, _Tp2>* __p, const std::pair<_Up, _Vp>& __pr)
269 {
270 this->construct(__p, piecewise_construct,
273 }
274
275 template<typename _Tp1, typename _Tp2, typename _Up, typename _Vp>
276 __attribute__((__nonnull__))
277 void
278 construct(pair<_Tp1, _Tp2>* __p, pair<_Up, _Vp>&& __pr)
279 {
280 this->construct(__p, piecewise_construct,
281 std::forward_as_tuple(std::forward<_Up>(__pr.first)),
282 std::forward_as_tuple(std::forward<_Vp>(__pr.second)));
283 }
284#else // make_obj_using_allocator
285 template<typename _Tp1, typename... _Args>
286 __attribute__((__nonnull__))
287 void
288 construct(_Tp1* __p, _Args&&... __args)
289 {
290 std::uninitialized_construct_using_allocator(__p, *this,
291 std::forward<_Args>(__args)...);
292 }
293#endif
294
295 template<typename _Up>
296 _GLIBCXX20_DEPRECATED_SUGGEST("allocator_traits::destroy")
297 __attribute__((__nonnull__))
298 void
299 destroy(_Up* __p)
300 { __p->~_Up(); }
301
302 polymorphic_allocator
303 select_on_container_copy_construction() const noexcept
304 { return polymorphic_allocator(); }
305
306 memory_resource*
307 resource() const noexcept
308 __attribute__((__returns_nonnull__))
309 { return _M_resource; }
310
311 // _GLIBCXX_RESOLVE_LIB_DEFECTS
312 // 3683. operator== for polymorphic_allocator cannot deduce template arg
313 [[nodiscard]]
314 friend bool
315 operator==(const polymorphic_allocator& __a,
316 const polymorphic_allocator& __b) noexcept
317 { return *__a.resource() == *__b.resource(); }
318
319#if __cpp_impl_three_way_comparison < 201907L
320 [[nodiscard]]
321 friend bool
322 operator!=(const polymorphic_allocator& __a,
323 const polymorphic_allocator& __b) noexcept
324 { return !(__a == __b); }
325#endif
326
327 private:
328#if ! __cpp_lib_make_obj_using_allocator
329 using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
330 using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
331
332 template<typename _Ind, typename... _Args>
333 static tuple<_Args&&...>
334 _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
335 { return std::move(__t); }
336
337 template<size_t... _Ind, typename... _Args>
338 static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...>
339 _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>,
340 tuple<_Args...>& __t)
341 {
342 return {
343 allocator_arg, *__ua._M_a, std::get<_Ind>(std::move(__t))...
344 };
345 }
346
347 template<size_t... _Ind, typename... _Args>
348 static tuple<_Args&&..., polymorphic_allocator>
349 _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>,
350 tuple<_Args...>& __t)
351 { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; }
352#endif
353
354 memory_resource* _M_resource;
355 };
356
357 template<typename _Tp1, typename _Tp2>
358 [[nodiscard]]
359 inline bool
360 operator==(const polymorphic_allocator<_Tp1>& __a,
361 const polymorphic_allocator<_Tp2>& __b) noexcept
362 { return *__a.resource() == *__b.resource(); }
363
364#if __cpp_impl_three_way_comparison < 201907L
365 template<typename _Tp1, typename _Tp2>
366 [[nodiscard]]
367 inline bool
368 operator!=(const polymorphic_allocator<_Tp1>& __a,
369 const polymorphic_allocator<_Tp2>& __b) noexcept
370 { return !(__a == __b); }
371#endif
372
373} // namespace pmr
374
375 template<typename _Alloc> struct allocator_traits;
376
377 /// Partial specialization for std::pmr::polymorphic_allocator
378 template<typename _Tp>
379 struct allocator_traits<pmr::polymorphic_allocator<_Tp>>
380 {
381 /// The allocator type
382 using allocator_type = pmr::polymorphic_allocator<_Tp>;
383
384 /// The allocated type
385 using value_type = _Tp;
386
387 /// The allocator's pointer type.
388 using pointer = _Tp*;
389
390 /// The allocator's const pointer type.
391 using const_pointer = const _Tp*;
392
393 /// The allocator's void pointer type.
394 using void_pointer = void*;
395
396 /// The allocator's const void pointer type.
397 using const_void_pointer = const void*;
398
399 /// The allocator's difference type
400 using difference_type = std::ptrdiff_t;
401
402 /// The allocator's size type
403 using size_type = std::size_t;
404
405 /** @{
406 * A `polymorphic_allocator` does not propagate when a
407 * container is copied, moved, or swapped.
408 */
412
413 static allocator_type
415 { return allocator_type(); }
416 /// @}
417
418 /// Whether all instances of the allocator type compare equal.
420
421 template<typename _Up>
422 using rebind_alloc = pmr::polymorphic_allocator<_Up>;
423
424 template<typename _Up>
426
427 /**
428 * @brief Allocate memory.
429 * @param __a An allocator.
430 * @param __n The number of objects to allocate space for.
431 *
432 * Calls `a.allocate(n)`.
433 */
434 [[nodiscard]] static pointer
436 { return __a.allocate(__n); }
437
438 /**
439 * @brief Allocate memory.
440 * @param __a An allocator.
441 * @param __n The number of objects to allocate space for.
442 * @return Memory of suitable size and alignment for `n` objects
443 * of type `value_type`.
444 *
445 * The third parameter is ignored..
446 *
447 * Returns `a.allocate(n)`.
448 */
449 [[nodiscard]] static pointer
451 { return __a.allocate(__n); }
452
453 /**
454 * @brief Deallocate memory.
455 * @param __a An allocator.
456 * @param __p Pointer to the memory to deallocate.
457 * @param __n The number of objects space was allocated for.
458 *
459 * Calls `a.deallocate(p, n)`.
460 */
461 static void
463 { __a.deallocate(__p, __n); }
464
465 /**
466 * @brief Construct an object of type `_Up`
467 * @param __a An allocator.
468 * @param __p Pointer to memory of suitable size and alignment for
469 * an object of type `_Up`.
470 * @param __args Constructor arguments.
471 *
472 * Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
473 * in C++11, C++14 and C++17. Changed in C++20 to call
474 * `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
475 */
476 template<typename _Up, typename... _Args>
477 static void
478 construct(allocator_type& __a, _Up* __p, _Args&&... __args)
479 { __a.construct(__p, std::forward<_Args>(__args)...); }
480
481 /**
482 * @brief Destroy an object of type `_Up`
483 * @param __a An allocator.
484 * @param __p Pointer to the object to destroy
485 *
486 * Calls `p->_Up()`.
487 */
488 template<typename _Up>
489 static _GLIBCXX20_CONSTEXPR void
492 { __p->~_Up(); }
493
494 /**
495 * @brief The maximum supported allocation size
496 * @return `numeric_limits<size_t>::max() / sizeof(value_type)`
497 */
498 static _GLIBCXX20_CONSTEXPR size_type
499 max_size(const allocator_type&) noexcept
500 { return size_t(-1) / sizeof(value_type); }
501 };
502
503_GLIBCXX_END_NAMESPACE_VERSION
504} // namespace std
505
506#endif // C++17
507#endif // _GLIBCXX_MEMORY_RESOURCE_H
memory_resource * get_default_resource() noexcept
Get the current default memory resource pointer.
constexpr tuple< _Elements &&... > forward_as_tuple(_Elements &&... __args) noexcept
Create a tuple of lvalue or rvalue references to the arguments.
Definition: tuple:1999
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:104
constexpr piecewise_construct_t piecewise_construct
Tag for piecewise construction of std::pair objects.
Definition: stl_pair.h:83
ISO C++ entities toplevel namespace is std.
make_index_sequence< sizeof...(_Types)> index_sequence_for
Alias template index_sequence_for.
Definition: utility.h:189
__numeric_traits_integer< _Tp > __int_traits
Convenience alias for __numeric_traits<integer-type>.
integral_constant
Definition: type_traits:63
is_nothrow_destructible
Definition: type_traits:1032
Uniform interface to all allocator types.
Class memory_resource.
static void construct(allocator_type &__a, _Up *__p, _Args &&... __args)
Construct an object of type _Up
std::ptrdiff_t difference_type
The allocator's difference type.
static void deallocate(allocator_type &__a, pointer __p, size_type __n)
Deallocate memory.
static constexpr void destroy(allocator_type &, _Up *__p) noexcept(is_nothrow_destructible< _Up >::value)
Destroy an object of type _Up
static constexpr size_type max_size(const allocator_type &) noexcept
The maximum supported allocation size.
static pointer allocate(allocator_type &__a, size_type __n)
Allocate memory.
const _Tp * const_pointer
The allocator's const pointer type.
static pointer allocate(allocator_type &__a, size_type __n, const_void_pointer)
Allocate memory.
const void * const_void_pointer
The allocator's const void pointer type.
static allocator_type select_on_container_copy_construction(const allocator_type &) noexcept
void * void_pointer
The allocator's void pointer type.
pmr::polymorphic_allocator< _Tp > allocator_type
The allocator type.
Struct holding two objects of arbitrary type.
Definition: stl_pair.h:189
_T1 first
The first member.
Definition: stl_pair.h:193
_T2 second
The second member.
Definition: stl_pair.h:194