1 // <memory_resource> -*- C++ -*-
3 // Copyright (C) 2018-2023 Free Software Foundation, Inc.
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
25 /** @file include/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}
30 #ifndef _GLIBCXX_MEMORY_RESOURCE_H
31 #define _GLIBCXX_MEMORY_RESOURCE_H 1
33 #pragma GCC system_header
35 #if __cplusplus >= 201703L
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>
45 #if ! __glibcxx_make_obj_using_allocator
46 # include <bits/utility.h> // index_sequence
47 # include <tuple> // tuple, forward_as_tuple
50 namespace std
_GLIBCXX_VISIBILITY(default)
52 _GLIBCXX_BEGIN_NAMESPACE_VERSION
55 /// Class memory_resource
58 * @headerfile memory_resource
63 static constexpr size_t _S_max_align
= alignof(max_align_t
);
66 memory_resource() = default;
67 memory_resource(const memory_resource
&) = default;
68 virtual ~memory_resource(); // key function
70 memory_resource
& operator=(const memory_resource
&) = default;
74 allocate(size_t __bytes
, size_t __alignment
= _S_max_align
)
75 __attribute__((__returns_nonnull__
,__alloc_size__(2),__alloc_align__(3)))
76 { return ::operator new(__bytes
, do_allocate(__bytes
, __alignment
)); }
79 deallocate(void* __p
, size_t __bytes
, size_t __alignment
= _S_max_align
)
80 __attribute__((__nonnull__
))
81 { return do_deallocate(__p
, __bytes
, __alignment
); }
85 is_equal(const memory_resource
& __other
) const noexcept
86 { return do_is_equal(__other
); }
90 do_allocate(size_t __bytes
, size_t __alignment
) = 0;
93 do_deallocate(void* __p
, size_t __bytes
, size_t __alignment
) = 0;
96 do_is_equal(const memory_resource
& __other
) const noexcept
= 0;
101 operator==(const memory_resource
& __a
, const memory_resource
& __b
) noexcept
102 { return &__a
== &__b
|| __a
.is_equal(__b
); }
104 #if __cpp_impl_three_way_comparison < 201907L
107 operator!=(const memory_resource
& __a
, const memory_resource
& __b
) noexcept
108 { return !(__a
== __b
); }
111 // C++17 23.12.3 Class template polymorphic_allocator
113 /// Class template polymorphic_allocator
116 * @headerfile memory_resource
119 template<typename _Tp
>
120 class polymorphic_allocator
122 // _GLIBCXX_RESOLVE_LIB_DEFECTS
123 // 2975. Missing case for pair construction in polymorphic allocators
124 template<typename _Up
>
125 struct __not_pair
{ using type
= void; };
127 template<typename _Up1
, typename _Up2
>
128 struct __not_pair
<pair
<_Up1
, _Up2
>> { };
131 using value_type
= _Tp
;
133 polymorphic_allocator() noexcept
135 extern memory_resource
* get_default_resource() noexcept
136 __attribute__((__returns_nonnull__
));
137 _M_resource
= get_default_resource();
140 polymorphic_allocator(memory_resource
* __r
) noexcept
141 __attribute__((__nonnull__
))
143 { _GLIBCXX_DEBUG_ASSERT(__r
); }
145 polymorphic_allocator(const polymorphic_allocator
& __other
) = default;
147 template<typename _Up
>
148 polymorphic_allocator(const polymorphic_allocator
<_Up
>& __x
) noexcept
149 : _M_resource(__x
.resource())
152 polymorphic_allocator
&
153 operator=(const polymorphic_allocator
&) = delete;
158 __attribute__((__returns_nonnull__
))
160 if ((__gnu_cxx::__int_traits
<size_t>::__max
/ sizeof(_Tp
)) < __n
)
161 std::__throw_bad_array_new_length();
162 return static_cast<_Tp
*>(_M_resource
->allocate(__n
* sizeof(_Tp
),
167 deallocate(_Tp
* __p
, size_t __n
) noexcept
168 __attribute__((__nonnull__
))
169 { _M_resource
->deallocate(__p
, __n
* sizeof(_Tp
), alignof(_Tp
)); }
171 #if __cplusplus > 201703L
173 allocate_bytes(size_t __nbytes
,
174 size_t __alignment
= alignof(max_align_t
))
175 { return _M_resource
->allocate(__nbytes
, __alignment
); }
178 deallocate_bytes(void* __p
, size_t __nbytes
,
179 size_t __alignment
= alignof(max_align_t
))
180 { _M_resource
->deallocate(__p
, __nbytes
, __alignment
); }
182 template<typename _Up
>
184 allocate_object(size_t __n
= 1)
186 if ((__gnu_cxx::__int_traits
<size_t>::__max
/ sizeof(_Up
)) < __n
)
187 std::__throw_bad_array_new_length();
188 return static_cast<_Up
*>(allocate_bytes(__n
* sizeof(_Up
),
192 template<typename _Up
>
194 deallocate_object(_Up
* __p
, size_t __n
= 1)
195 { deallocate_bytes(__p
, __n
* sizeof(_Up
), alignof(_Up
)); }
197 template<typename _Up
, typename
... _CtorArgs
>
199 new_object(_CtorArgs
&&... __ctor_args
)
201 _Up
* __p
= allocate_object
<_Up
>();
204 construct(__p
, std::forward
<_CtorArgs
>(__ctor_args
)...);
208 deallocate_object(__p
);
209 __throw_exception_again
;
214 template<typename _Up
>
216 delete_object(_Up
* __p
)
219 deallocate_object(__p
);
223 #if ! __glibcxx_make_obj_using_allocator
224 template<typename _Tp1
, typename
... _Args
>
225 __attribute__((__nonnull__
))
226 typename __not_pair
<_Tp1
>::type
227 construct(_Tp1
* __p
, _Args
&&... __args
)
229 // _GLIBCXX_RESOLVE_LIB_DEFECTS
230 // 2969. polymorphic_allocator::construct() shouldn't pass resource()
232 = std::__uses_alloc_t
<_Tp1
, polymorphic_allocator
, _Args
...>;
233 if constexpr (is_base_of_v
<__uses_alloc0
, __use_tag
>)
234 ::new(__p
) _Tp1(std::forward
<_Args
>(__args
)...);
235 else if constexpr (is_base_of_v
<__uses_alloc1_
, __use_tag
>)
236 ::new(__p
) _Tp1(allocator_arg
, *this,
237 std::forward
<_Args
>(__args
)...);
239 ::new(__p
) _Tp1(std::forward
<_Args
>(__args
)..., *this);
242 template<typename _Tp1
, typename _Tp2
,
243 typename
... _Args1
, typename
... _Args2
>
244 __attribute__((__nonnull__
))
246 construct(pair
<_Tp1
, _Tp2
>* __p
, piecewise_construct_t
,
247 tuple
<_Args1
...> __x
, tuple
<_Args2
...> __y
)
250 __use_alloc
<_Tp1
, polymorphic_allocator
, _Args1
...>(*this);
252 __use_alloc
<_Tp2
, polymorphic_allocator
, _Args2
...>(*this);
253 index_sequence_for
<_Args1
...> __x_i
;
254 index_sequence_for
<_Args2
...> __y_i
;
256 ::new(__p
) pair
<_Tp1
, _Tp2
>(piecewise_construct
,
257 _S_construct_p(__x_tag
, __x_i
, __x
),
258 _S_construct_p(__y_tag
, __y_i
, __y
));
261 template<typename _Tp1
, typename _Tp2
>
262 __attribute__((__nonnull__
))
264 construct(pair
<_Tp1
, _Tp2
>* __p
)
265 { this->construct(__p
, piecewise_construct
, tuple
<>(), tuple
<>()); }
267 template<typename _Tp1
, typename _Tp2
, typename _Up
, typename _Vp
>
268 __attribute__((__nonnull__
))
270 construct(pair
<_Tp1
, _Tp2
>* __p
, _Up
&& __x
, _Vp
&& __y
)
272 this->construct(__p
, piecewise_construct
,
273 std::forward_as_tuple(std::forward
<_Up
>(__x
)),
274 std::forward_as_tuple(std::forward
<_Vp
>(__y
)));
277 template <typename _Tp1
, typename _Tp2
, typename _Up
, typename _Vp
>
278 __attribute__((__nonnull__
))
280 construct(pair
<_Tp1
, _Tp2
>* __p
, const std::pair
<_Up
, _Vp
>& __pr
)
282 this->construct(__p
, piecewise_construct
,
283 std::forward_as_tuple(__pr
.first
),
284 std::forward_as_tuple(__pr
.second
));
287 template<typename _Tp1
, typename _Tp2
, typename _Up
, typename _Vp
>
288 __attribute__((__nonnull__
))
290 construct(pair
<_Tp1
, _Tp2
>* __p
, pair
<_Up
, _Vp
>&& __pr
)
292 this->construct(__p
, piecewise_construct
,
293 std::forward_as_tuple(std::forward
<_Up
>(__pr
.first
)),
294 std::forward_as_tuple(std::forward
<_Vp
>(__pr
.second
)));
296 #else // make_obj_using_allocator
297 template<typename _Tp1
, typename
... _Args
>
298 __attribute__((__nonnull__
))
300 construct(_Tp1
* __p
, _Args
&&... __args
)
302 std::uninitialized_construct_using_allocator(__p
, *this,
303 std::forward
<_Args
>(__args
)...);
307 template<typename _Up
>
308 _GLIBCXX20_DEPRECATED_SUGGEST("allocator_traits::destroy")
309 __attribute__((__nonnull__
))
314 polymorphic_allocator
315 select_on_container_copy_construction() const noexcept
316 { return polymorphic_allocator(); }
319 resource() const noexcept
320 __attribute__((__returns_nonnull__
))
321 { return _M_resource
; }
323 // _GLIBCXX_RESOLVE_LIB_DEFECTS
324 // 3683. operator== for polymorphic_allocator cannot deduce template arg
327 operator==(const polymorphic_allocator
& __a
,
328 const polymorphic_allocator
& __b
) noexcept
329 { return *__a
.resource() == *__b
.resource(); }
331 #if __cpp_impl_three_way_comparison < 201907L
334 operator!=(const polymorphic_allocator
& __a
,
335 const polymorphic_allocator
& __b
) noexcept
336 { return !(__a
== __b
); }
340 #if ! __glibcxx_make_obj_using_allocator
341 using __uses_alloc1_
= __uses_alloc1
<polymorphic_allocator
>;
342 using __uses_alloc2_
= __uses_alloc2
<polymorphic_allocator
>;
344 template<typename _Ind
, typename
... _Args
>
345 static tuple
<_Args
&&...>
346 _S_construct_p(__uses_alloc0
, _Ind
, tuple
<_Args
...>& __t
)
347 { return std::move(__t
); }
349 template<size_t... _Ind
, typename
... _Args
>
350 static tuple
<allocator_arg_t
, polymorphic_allocator
, _Args
&&...>
351 _S_construct_p(__uses_alloc1_ __ua
, index_sequence
<_Ind
...>,
352 tuple
<_Args
...>& __t
)
355 allocator_arg
, *__ua
._M_a
, std::get
<_Ind
>(std::move(__t
))...
359 template<size_t... _Ind
, typename
... _Args
>
360 static tuple
<_Args
&&..., polymorphic_allocator
>
361 _S_construct_p(__uses_alloc2_ __ua
, index_sequence
<_Ind
...>,
362 tuple
<_Args
...>& __t
)
363 { return { std::get
<_Ind
>(std::move(__t
))..., *__ua
._M_a
}; }
366 memory_resource
* _M_resource
;
369 template<typename _Tp1
, typename _Tp2
>
372 operator==(const polymorphic_allocator
<_Tp1
>& __a
,
373 const polymorphic_allocator
<_Tp2
>& __b
) noexcept
374 { return *__a
.resource() == *__b
.resource(); }
376 #if __cpp_impl_three_way_comparison < 201907L
377 template<typename _Tp1
, typename _Tp2
>
380 operator!=(const polymorphic_allocator
<_Tp1
>& __a
,
381 const polymorphic_allocator
<_Tp2
>& __b
) noexcept
382 { return !(__a
== __b
); }
387 template<typename _Alloc
> struct allocator_traits
;
389 /// Partial specialization for std::pmr::polymorphic_allocator
390 template<typename _Tp
>
391 struct allocator_traits
<pmr::polymorphic_allocator
<_Tp
>>
393 /// The allocator type
394 using allocator_type
= pmr::polymorphic_allocator
<_Tp
>;
396 /// The allocated type
397 using value_type
= _Tp
;
399 /// The allocator's pointer type.
400 using pointer
= _Tp
*;
402 /// The allocator's const pointer type.
403 using const_pointer
= const _Tp
*;
405 /// The allocator's void pointer type.
406 using void_pointer
= void*;
408 /// The allocator's const void pointer type.
409 using const_void_pointer
= const void*;
411 /// The allocator's difference type
412 using difference_type
= std::ptrdiff_t;
414 /// The allocator's size type
415 using size_type
= std::size_t;
418 * A `polymorphic_allocator` does not propagate when a
419 * container is copied, moved, or swapped.
421 using propagate_on_container_copy_assignment
= false_type
;
422 using propagate_on_container_move_assignment
= false_type
;
423 using propagate_on_container_swap
= false_type
;
425 static allocator_type
426 select_on_container_copy_construction(const allocator_type
&) noexcept
427 { return allocator_type(); }
430 /// Whether all instances of the allocator type compare equal.
431 using is_always_equal
= false_type
;
433 template<typename _Up
>
434 using rebind_alloc
= pmr::polymorphic_allocator
<_Up
>;
436 template<typename _Up
>
437 using rebind_traits
= allocator_traits
<pmr::polymorphic_allocator
<_Up
>>;
440 * @brief Allocate memory.
441 * @param __a An allocator.
442 * @param __n The number of objects to allocate space for.
444 * Calls `a.allocate(n)`.
446 [[nodiscard
]] static pointer
447 allocate(allocator_type
& __a
, size_type __n
)
448 { return __a
.allocate(__n
); }
451 * @brief Allocate memory.
452 * @param __a An allocator.
453 * @param __n The number of objects to allocate space for.
454 * @return Memory of suitable size and alignment for `n` objects
455 * of type `value_type`.
457 * The third parameter is ignored..
459 * Returns `a.allocate(n)`.
461 [[nodiscard
]] static pointer
462 allocate(allocator_type
& __a
, size_type __n
, const_void_pointer
)
463 { return __a
.allocate(__n
); }
466 * @brief Deallocate memory.
467 * @param __a An allocator.
468 * @param __p Pointer to the memory to deallocate.
469 * @param __n The number of objects space was allocated for.
471 * Calls `a.deallocate(p, n)`.
474 deallocate(allocator_type
& __a
, pointer __p
, size_type __n
)
475 { __a
.deallocate(__p
, __n
); }
478 * @brief Construct an object of type `_Up`
479 * @param __a An allocator.
480 * @param __p Pointer to memory of suitable size and alignment for
481 * an object of type `_Up`.
482 * @param __args Constructor arguments.
484 * Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
485 * in C++11, C++14 and C++17. Changed in C++20 to call
486 * `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
488 template<typename _Up
, typename
... _Args
>
490 construct(allocator_type
& __a
, _Up
* __p
, _Args
&&... __args
)
491 { __a
.construct(__p
, std::forward
<_Args
>(__args
)...); }
494 * @brief Destroy an object of type `_Up`
495 * @param __a An allocator.
496 * @param __p Pointer to the object to destroy
500 template<typename _Up
>
501 static _GLIBCXX20_CONSTEXPR
void
502 destroy(allocator_type
&, _Up
* __p
)
503 noexcept(is_nothrow_destructible
<_Up
>::value
)
507 * @brief The maximum supported allocation size
508 * @return `numeric_limits<size_t>::max() / sizeof(value_type)`
510 static _GLIBCXX20_CONSTEXPR size_type
511 max_size(const allocator_type
&) noexcept
512 { return size_t(-1) / sizeof(value_type
); }
515 _GLIBCXX_END_NAMESPACE_VERSION
519 #endif // _GLIBCXX_MEMORY_RESOURCE_H