libstdc++: Only declare feature test macros in standard headers
[official-gcc.git] / libstdc++-v3 / include / bits / memory_resource.h
blob97bcdd5e5723251cfb476dd5a21a596a39f290a3
1 // <memory_resource> -*- C++ -*-
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.
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
48 #endif
50 namespace std _GLIBCXX_VISIBILITY(default)
52 _GLIBCXX_BEGIN_NAMESPACE_VERSION
53 namespace pmr
55 /// Class memory_resource
56 /**
57 * @ingroup pmr
58 * @headerfile memory_resource
59 * @since C++17
61 class memory_resource
63 static constexpr size_t _S_max_align = alignof(max_align_t);
65 public:
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;
72 [[nodiscard]]
73 void*
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)); }
78 void
79 deallocate(void* __p, size_t __bytes, size_t __alignment = _S_max_align)
80 __attribute__((__nonnull__))
81 { return do_deallocate(__p, __bytes, __alignment); }
83 [[nodiscard]]
84 bool
85 is_equal(const memory_resource& __other) const noexcept
86 { return do_is_equal(__other); }
88 private:
89 virtual void*
90 do_allocate(size_t __bytes, size_t __alignment) = 0;
92 virtual void
93 do_deallocate(void* __p, size_t __bytes, size_t __alignment) = 0;
95 virtual bool
96 do_is_equal(const memory_resource& __other) const noexcept = 0;
99 [[nodiscard]]
100 inline bool
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
105 [[nodiscard]]
106 inline bool
107 operator!=(const memory_resource& __a, const memory_resource& __b) noexcept
108 { return !(__a == __b); }
109 #endif
111 // C++17 23.12.3 Class template polymorphic_allocator
113 /// Class template polymorphic_allocator
115 * @ingroup pmr
116 * @headerfile memory_resource
117 * @since C++17
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>> { };
130 public:
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__))
142 : _M_resource(__r)
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;
155 [[nodiscard]]
156 _Tp*
157 allocate(size_t __n)
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),
163 alignof(_Tp)));
166 void
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
172 [[nodiscard]] void*
173 allocate_bytes(size_t __nbytes,
174 size_t __alignment = alignof(max_align_t))
175 { return _M_resource->allocate(__nbytes, __alignment); }
177 void
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>
183 [[nodiscard]] _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),
189 alignof(_Up)));
192 template<typename _Up>
193 void
194 deallocate_object(_Up* __p, size_t __n = 1)
195 { deallocate_bytes(__p, __n * sizeof(_Up), alignof(_Up)); }
197 template<typename _Up, typename... _CtorArgs>
198 [[nodiscard]] _Up*
199 new_object(_CtorArgs&&... __ctor_args)
201 _Up* __p = allocate_object<_Up>();
202 __try
204 construct(__p, std::forward<_CtorArgs>(__ctor_args)...);
206 __catch (...)
208 deallocate_object(__p);
209 __throw_exception_again;
211 return __p;
214 template<typename _Up>
215 void
216 delete_object(_Up* __p)
218 __p->~_Up();
219 deallocate_object(__p);
221 #endif // C++2a
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()
231 using __use_tag
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)...);
238 else
239 ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this);
242 template<typename _Tp1, typename _Tp2,
243 typename... _Args1, typename... _Args2>
244 __attribute__((__nonnull__))
245 void
246 construct(pair<_Tp1, _Tp2>* __p, piecewise_construct_t,
247 tuple<_Args1...> __x, tuple<_Args2...> __y)
249 auto __x_tag =
250 __use_alloc<_Tp1, polymorphic_allocator, _Args1...>(*this);
251 auto __y_tag =
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__))
263 void
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__))
269 void
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__))
279 void
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__))
289 void
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__))
299 void
300 construct(_Tp1* __p, _Args&&... __args)
302 std::uninitialized_construct_using_allocator(__p, *this,
303 std::forward<_Args>(__args)...);
305 #endif
307 template<typename _Up>
308 _GLIBCXX20_DEPRECATED_SUGGEST("allocator_traits::destroy")
309 __attribute__((__nonnull__))
310 void
311 destroy(_Up* __p)
312 { __p->~_Up(); }
314 polymorphic_allocator
315 select_on_container_copy_construction() const noexcept
316 { return polymorphic_allocator(); }
318 memory_resource*
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
325 [[nodiscard]]
326 friend bool
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
332 [[nodiscard]]
333 friend bool
334 operator!=(const polymorphic_allocator& __a,
335 const polymorphic_allocator& __b) noexcept
336 { return !(__a == __b); }
337 #endif
339 private:
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)
354 return {
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 }; }
364 #endif
366 memory_resource* _M_resource;
369 template<typename _Tp1, typename _Tp2>
370 [[nodiscard]]
371 inline bool
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>
378 [[nodiscard]]
379 inline bool
380 operator!=(const polymorphic_allocator<_Tp1>& __a,
381 const polymorphic_allocator<_Tp2>& __b) noexcept
382 { return !(__a == __b); }
383 #endif
385 } // namespace pmr
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;
417 /** @{
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(); }
428 /// @}
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)`.
473 static void
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>
489 static void
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
498 * Calls `p->_Up()`.
500 template<typename _Up>
501 static _GLIBCXX20_CONSTEXPR void
502 destroy(allocator_type&, _Up* __p)
503 noexcept(is_nothrow_destructible<_Up>::value)
504 { __p->~_Up(); }
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
516 } // namespace std
518 #endif // C++17
519 #endif // _GLIBCXX_MEMORY_RESOURCE_H