Line data Source code
1 : // Allocator traits -*- C++ -*-
2 :
3 : // Copyright (C) 2011-2024 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 bits/alloc_traits.h
26 : * This is an internal header file, included by other library headers.
27 : * Do not attempt to use it directly. @headername{memory}
28 : */
29 :
30 : #ifndef _ALLOC_TRAITS_H
31 : #define _ALLOC_TRAITS_H 1
32 :
33 : #include <bits/stl_construct.h>
34 : #include <bits/memoryfwd.h>
35 : #if __cplusplus >= 201103L
36 : # include <bits/ptr_traits.h>
37 : # include <ext/numeric_traits.h>
38 : # if _GLIBCXX_HOSTED
39 : # include <bits/allocator.h>
40 : # endif
41 : # if __cpp_exceptions
42 : # include <bits/stl_iterator.h> // __make_move_if_noexcept_iterator
43 : # endif
44 : #endif
45 :
46 : namespace std _GLIBCXX_VISIBILITY(default)
47 : {
48 : _GLIBCXX_BEGIN_NAMESPACE_VERSION
49 :
50 : #if __cplusplus >= 201103L
51 :
52 : #pragma GCC diagnostic push
53 : #pragma GCC diagnostic ignored "-Wc++14-extensions" // for variable templates
54 : #pragma GCC diagnostic ignored "-Wc++17-extensions" // for if-constexpr
55 :
56 : /// @cond undocumented
57 : struct __allocator_traits_base
58 : {
59 : template<typename _Tp, typename _Up, typename = void>
60 : struct __rebind : __replace_first_arg<_Tp, _Up>
61 : {
62 : static_assert(is_same<
63 : typename __replace_first_arg<_Tp, typename _Tp::value_type>::type,
64 : _Tp>::value,
65 : "allocator_traits<A>::rebind_alloc<A::value_type> must be A");
66 : };
67 :
68 : template<typename _Tp, typename _Up>
69 : struct __rebind<_Tp, _Up,
70 : __void_t<typename _Tp::template rebind<_Up>::other>>
71 : {
72 : using type = typename _Tp::template rebind<_Up>::other;
73 :
74 : static_assert(is_same<
75 : typename _Tp::template rebind<typename _Tp::value_type>::other,
76 : _Tp>::value,
77 : "allocator_traits<A>::rebind_alloc<A::value_type> must be A");
78 : };
79 :
80 : protected:
81 : template<typename _Tp>
82 : using __pointer = typename _Tp::pointer;
83 : template<typename _Tp>
84 : using __c_pointer = typename _Tp::const_pointer;
85 : template<typename _Tp>
86 : using __v_pointer = typename _Tp::void_pointer;
87 : template<typename _Tp>
88 : using __cv_pointer = typename _Tp::const_void_pointer;
89 : template<typename _Tp>
90 : using __pocca = typename _Tp::propagate_on_container_copy_assignment;
91 : template<typename _Tp>
92 : using __pocma = typename _Tp::propagate_on_container_move_assignment;
93 : template<typename _Tp>
94 : using __pocs = typename _Tp::propagate_on_container_swap;
95 : template<typename _Tp>
96 : using __equal = __type_identity<typename _Tp::is_always_equal>;
97 :
98 : // __has_construct is true if a.construct(p, args...) is well-formed.
99 : // __can_construct is true if either __has_construct is true, or if
100 : // a placement new-expression for T(args...) is well-formed. We use this
101 : // to constrain allocator_traits::construct, as a libstdc++ extension.
102 : template<typename _Alloc, typename _Tp, typename... _Args>
103 : using __construct_t
104 : = decltype(std::declval<_Alloc&>().construct(std::declval<_Tp*>(),
105 : std::declval<_Args>()...));
106 : template<typename _Alloc, typename _Tp, typename, typename... _Args>
107 : static constexpr bool __has_construct_impl = false;
108 : template<typename _Alloc, typename _Tp, typename... _Args>
109 : static constexpr bool
110 : __has_construct_impl<_Alloc, _Tp,
111 : __void_t<__construct_t<_Alloc, _Tp, _Args...>>,
112 : _Args...>
113 : = true;
114 : template<typename _Alloc, typename _Tp, typename... _Args>
115 : static constexpr bool __has_construct
116 : = __has_construct_impl<_Alloc, _Tp, void, _Args...>;
117 : template<typename _Tp, typename... _Args>
118 : using __new_expr_t
119 : = decltype(::new((void*)0) _Tp(std::declval<_Args>()...));
120 : template<typename _Tp, typename, typename... _Args>
121 : static constexpr bool __has_new_expr = false;
122 : template<typename _Tp, typename... _Args>
123 : static constexpr bool
124 : __has_new_expr<_Tp, __void_t<__new_expr_t<_Tp, _Args...>>, _Args...>
125 : = true;
126 : template<typename _Alloc, typename _Tp, typename... _Args>
127 : static constexpr bool __can_construct
128 : = __has_construct<_Alloc, _Tp, _Args...>
129 : || __has_new_expr<_Tp, void, _Args...>;
130 : };
131 :
132 : template<typename _Alloc, typename _Up>
133 : using __alloc_rebind
134 : = typename __allocator_traits_base::template __rebind<_Alloc, _Up>::type;
135 : /// @endcond
136 :
137 : /**
138 : * @brief Uniform interface to all allocator types.
139 : * @headerfile memory
140 : * @ingroup allocators
141 : * @since C++11
142 : */
143 : template<typename _Alloc>
144 : struct allocator_traits : __allocator_traits_base
145 : {
146 : /// The allocator type
147 : typedef _Alloc allocator_type;
148 : /// The allocated type
149 : typedef typename _Alloc::value_type value_type;
150 :
151 : /**
152 : * @brief The allocator's pointer type.
153 : *
154 : * @c Alloc::pointer if that type exists, otherwise @c value_type*
155 : */
156 : using pointer = __detected_or_t<value_type*, __pointer, _Alloc>;
157 :
158 : private:
159 : // Select _Func<_Alloc> or pointer_traits<pointer>::rebind<_Tp>
160 : template<template<typename> class _Func, typename _Tp, typename = void>
161 : struct _Ptr
162 : {
163 : using type = typename pointer_traits<pointer>::template rebind<_Tp>;
164 : };
165 :
166 : template<template<typename> class _Func, typename _Tp>
167 : struct _Ptr<_Func, _Tp, __void_t<_Func<_Alloc>>>
168 : {
169 : using type = _Func<_Alloc>;
170 : };
171 :
172 : // Select _A2::difference_type or pointer_traits<_Ptr>::difference_type
173 : template<typename _A2, typename _PtrT, typename = void>
174 : struct _Diff
175 : { using type = typename pointer_traits<_PtrT>::difference_type; };
176 :
177 : template<typename _A2, typename _PtrT>
178 : struct _Diff<_A2, _PtrT, __void_t<typename _A2::difference_type>>
179 : { using type = typename _A2::difference_type; };
180 :
181 : // Select _A2::size_type or make_unsigned<_DiffT>::type
182 : template<typename _A2, typename _DiffT, typename = void>
183 : struct _Size : make_unsigned<_DiffT> { };
184 :
185 : template<typename _A2, typename _DiffT>
186 : struct _Size<_A2, _DiffT, __void_t<typename _A2::size_type>>
187 : { using type = typename _A2::size_type; };
188 :
189 : public:
190 : /**
191 : * @brief The allocator's const pointer type.
192 : *
193 : * @c Alloc::const_pointer if that type exists, otherwise
194 : * <tt> pointer_traits<pointer>::rebind<const value_type> </tt>
195 : */
196 : using const_pointer = typename _Ptr<__c_pointer, const value_type>::type;
197 :
198 : /**
199 : * @brief The allocator's void pointer type.
200 : *
201 : * @c Alloc::void_pointer if that type exists, otherwise
202 : * <tt> pointer_traits<pointer>::rebind<void> </tt>
203 : */
204 : using void_pointer = typename _Ptr<__v_pointer, void>::type;
205 :
206 : /**
207 : * @brief The allocator's const void pointer type.
208 : *
209 : * @c Alloc::const_void_pointer if that type exists, otherwise
210 : * <tt> pointer_traits<pointer>::rebind<const void> </tt>
211 : */
212 : using const_void_pointer = typename _Ptr<__cv_pointer, const void>::type;
213 :
214 : /**
215 : * @brief The allocator's difference type
216 : *
217 : * @c Alloc::difference_type if that type exists, otherwise
218 : * <tt> pointer_traits<pointer>::difference_type </tt>
219 : */
220 : using difference_type = typename _Diff<_Alloc, pointer>::type;
221 :
222 : /**
223 : * @brief The allocator's size type
224 : *
225 : * @c Alloc::size_type if that type exists, otherwise
226 : * <tt> make_unsigned<difference_type>::type </tt>
227 : */
228 : using size_type = typename _Size<_Alloc, difference_type>::type;
229 :
230 : /**
231 : * @brief How the allocator is propagated on copy assignment
232 : *
233 : * @c Alloc::propagate_on_container_copy_assignment if that type exists,
234 : * otherwise @c false_type
235 : */
236 : using propagate_on_container_copy_assignment
237 : = __detected_or_t<false_type, __pocca, _Alloc>;
238 :
239 : /**
240 : * @brief How the allocator is propagated on move assignment
241 : *
242 : * @c Alloc::propagate_on_container_move_assignment if that type exists,
243 : * otherwise @c false_type
244 : */
245 : using propagate_on_container_move_assignment
246 : = __detected_or_t<false_type, __pocma, _Alloc>;
247 :
248 : /**
249 : * @brief How the allocator is propagated on swap
250 : *
251 : * @c Alloc::propagate_on_container_swap if that type exists,
252 : * otherwise @c false_type
253 : */
254 : using propagate_on_container_swap
255 : = __detected_or_t<false_type, __pocs, _Alloc>;
256 :
257 : /**
258 : * @brief Whether all instances of the allocator type compare equal.
259 : *
260 : * @c Alloc::is_always_equal if that type exists,
261 : * otherwise @c is_empty<Alloc>::type
262 : */
263 : using is_always_equal
264 : = typename __detected_or_t<is_empty<_Alloc>, __equal, _Alloc>::type;
265 :
266 : template<typename _Tp>
267 : using rebind_alloc = __alloc_rebind<_Alloc, _Tp>;
268 : template<typename _Tp>
269 : using rebind_traits = allocator_traits<rebind_alloc<_Tp>>;
270 :
271 : private:
272 : template<typename _Alloc2>
273 : static constexpr auto
274 : _S_allocate(_Alloc2& __a, size_type __n, const_void_pointer __hint, int)
275 : -> decltype(__a.allocate(__n, __hint))
276 : { return __a.allocate(__n, __hint); }
277 :
278 : template<typename _Alloc2>
279 : static constexpr pointer
280 : _S_allocate(_Alloc2& __a, size_type __n, const_void_pointer, ...)
281 : { return __a.allocate(__n); }
282 :
283 :
284 : template<typename _Alloc2, typename _Tp>
285 : static _GLIBCXX14_CONSTEXPR auto
286 : _S_destroy(_Alloc2& __a, _Tp* __p, int)
287 : noexcept(noexcept(__a.destroy(__p)))
288 : -> decltype(__a.destroy(__p))
289 : { __a.destroy(__p); }
290 :
291 : template<typename _Alloc2, typename _Tp>
292 : static _GLIBCXX14_CONSTEXPR void
293 : _S_destroy(_Alloc2&, _Tp* __p, ...)
294 : noexcept(std::is_nothrow_destructible<_Tp>::value)
295 : { std::_Destroy(__p); }
296 :
297 : template<typename _Alloc2>
298 : static constexpr auto
299 : _S_max_size(_Alloc2& __a, int)
300 : -> decltype(__a.max_size())
301 : { return __a.max_size(); }
302 :
303 : template<typename _Alloc2>
304 : static constexpr size_type
305 : _S_max_size(_Alloc2&, ...)
306 : {
307 : // _GLIBCXX_RESOLVE_LIB_DEFECTS
308 : // 2466. allocator_traits::max_size() default behavior is incorrect
309 : return __gnu_cxx::__numeric_traits<size_type>::__max
310 : / sizeof(value_type);
311 : }
312 :
313 : template<typename _Alloc2>
314 : static constexpr auto
315 : _S_select(_Alloc2& __a, int)
316 : -> decltype(__a.select_on_container_copy_construction())
317 : { return __a.select_on_container_copy_construction(); }
318 :
319 : template<typename _Alloc2>
320 : static constexpr _Alloc2
321 : _S_select(_Alloc2& __a, ...)
322 : { return __a; }
323 :
324 : public:
325 :
326 : /**
327 : * @brief Allocate memory.
328 : * @param __a An allocator.
329 : * @param __n The number of objects to allocate space for.
330 : *
331 : * Calls @c a.allocate(n)
332 : */
333 : _GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
334 : allocate(_Alloc& __a, size_type __n)
335 : { return __a.allocate(__n); }
336 :
337 : /**
338 : * @brief Allocate memory.
339 : * @param __a An allocator.
340 : * @param __n The number of objects to allocate space for.
341 : * @param __hint Aid to locality.
342 : * @return Memory of suitable size and alignment for @a n objects
343 : * of type @c value_type
344 : *
345 : * Returns <tt> a.allocate(n, hint) </tt> if that expression is
346 : * well-formed, otherwise returns @c a.allocate(n)
347 : */
348 : _GLIBCXX_NODISCARD static _GLIBCXX20_CONSTEXPR pointer
349 : allocate(_Alloc& __a, size_type __n, const_void_pointer __hint)
350 : { return _S_allocate(__a, __n, __hint, 0); }
351 :
352 : /**
353 : * @brief Deallocate memory.
354 : * @param __a An allocator.
355 : * @param __p Pointer to the memory to deallocate.
356 : * @param __n The number of objects space was allocated for.
357 : *
358 : * Calls <tt> a.deallocate(p, n) </tt>
359 : */
360 : static _GLIBCXX20_CONSTEXPR void
361 : deallocate(_Alloc& __a, pointer __p, size_type __n)
362 : { __a.deallocate(__p, __n); }
363 :
364 : /**
365 : * @brief Construct an object of type `_Tp`
366 : * @param __a An allocator.
367 : * @param __p Pointer to memory of suitable size and alignment for Tp
368 : * @param __args Constructor arguments.
369 : *
370 : * Calls <tt> __a.construct(__p, std::forward<Args>(__args)...) </tt>
371 : * if that expression is well-formed, otherwise uses placement-new
372 : * to construct an object of type @a _Tp at location @a __p from the
373 : * arguments @a __args...
374 : */
375 : template<typename _Tp, typename... _Args>
376 : static _GLIBCXX20_CONSTEXPR
377 : __enable_if_t<__can_construct<_Alloc, _Tp, _Args...>>
378 : construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
379 : noexcept(_S_nothrow_construct<_Tp, _Args...>())
380 : {
381 : if constexpr (__has_construct<_Alloc, _Tp, _Args...>)
382 : __a.construct(__p, std::forward<_Args>(__args)...);
383 : else
384 : std::_Construct(__p, std::forward<_Args>(__args)...);
385 : }
386 :
387 : /**
388 : * @brief Destroy an object of type @a _Tp
389 : * @param __a An allocator.
390 : * @param __p Pointer to the object to destroy
391 : *
392 : * Calls @c __a.destroy(__p) if that expression is well-formed,
393 : * otherwise calls @c __p->~_Tp()
394 : */
395 : template<typename _Tp>
396 : static _GLIBCXX20_CONSTEXPR void
397 : destroy(_Alloc& __a, _Tp* __p)
398 : noexcept(noexcept(_S_destroy(__a, __p, 0)))
399 : { _S_destroy(__a, __p, 0); }
400 :
401 : /**
402 : * @brief The maximum supported allocation size
403 : * @param __a An allocator.
404 : * @return @c __a.max_size() or @c numeric_limits<size_type>::max()
405 : *
406 : * Returns @c __a.max_size() if that expression is well-formed,
407 : * otherwise returns @c numeric_limits<size_type>::max()
408 : */
409 : static _GLIBCXX20_CONSTEXPR size_type
410 : max_size(const _Alloc& __a) noexcept
411 : { return _S_max_size(__a, 0); }
412 :
413 : /**
414 : * @brief Obtain an allocator to use when copying a container.
415 : * @param __rhs An allocator.
416 : * @return @c __rhs.select_on_container_copy_construction() or @a __rhs
417 : *
418 : * Returns @c __rhs.select_on_container_copy_construction() if that
419 : * expression is well-formed, otherwise returns @a __rhs
420 : */
421 : static _GLIBCXX20_CONSTEXPR _Alloc
422 : select_on_container_copy_construction(const _Alloc& __rhs)
423 : { return _S_select(__rhs, 0); }
424 :
425 : private:
426 : #if __cpp_constexpr >= 201304 // >= C++14
427 : template<typename _Tp, typename... _Args>
428 : static constexpr bool
429 : _S_nothrow_construct(_Alloc* __a = nullptr, _Tp* __p = nullptr)
430 : {
431 : if constexpr (__has_construct<_Alloc, _Tp, _Args...>)
432 : return noexcept(__a->construct(__p, std::declval<_Args>()...));
433 : else
434 : return __is_nothrow_new_constructible<_Tp, _Args...>;
435 : }
436 : #else
437 : template<typename _Tp, typename... _Args>
438 : static constexpr
439 : __enable_if_t<__has_construct<_Alloc, _Tp, _Args...>, bool>
440 : _S_nothrow_construct(_Alloc* __a = nullptr, _Tp* __p = nullptr)
441 : { return noexcept(__a->construct(__p, std::declval<_Args>()...)); }
442 :
443 : template<typename _Tp, typename... _Args>
444 : static constexpr
445 : __enable_if_t<!__has_construct<_Alloc, _Tp, _Args...>, bool>
446 : _S_nothrow_construct(_Alloc* = nullptr, _Tp* __p = nullptr)
447 : { return __is_nothrow_new_constructible<_Tp, _Args...>; }
448 : #endif
449 : };
450 : #pragma GCC diagnostic pop
451 :
452 : #if _GLIBCXX_HOSTED
453 : /**
454 : * @brief Partial specialization for `std::allocator`
455 : * @headerfile memory
456 : * @ingroup allocators
457 : * @since C++11
458 : * @see std::allocator_traits
459 : */
460 : template<typename _Tp>
461 : struct allocator_traits<allocator<_Tp>>
462 : {
463 : /// The allocator type
464 : using allocator_type = allocator<_Tp>;
465 :
466 : /// The allocated type
467 : using value_type = _Tp;
468 :
469 : /// The allocator's pointer type.
470 : using pointer = _Tp*;
471 :
472 : /// The allocator's const pointer type.
473 : using const_pointer = const _Tp*;
474 :
475 : /// The allocator's void pointer type.
476 : using void_pointer = void*;
477 :
478 : /// The allocator's const void pointer type.
479 : using const_void_pointer = const void*;
480 :
481 : /// The allocator's difference type
482 : using difference_type = std::ptrdiff_t;
483 :
484 : /// The allocator's size type
485 : using size_type = std::size_t;
486 :
487 : /// How the allocator is propagated on copy assignment
488 : using propagate_on_container_copy_assignment = false_type;
489 :
490 : /// How the allocator is propagated on move assignment
491 : using propagate_on_container_move_assignment = true_type;
492 :
493 : /// How the allocator is propagated on swap
494 : using propagate_on_container_swap = false_type;
495 :
496 : /// Whether all instances of the allocator type compare equal.
497 : using is_always_equal = true_type;
498 :
499 : template<typename _Up>
500 : using rebind_alloc = allocator<_Up>;
501 :
502 : template<typename _Up>
503 : using rebind_traits = allocator_traits<allocator<_Up>>;
504 :
505 : /**
506 : * @brief Allocate memory.
507 : * @param __a An allocator.
508 : * @param __n The number of objects to allocate space for.
509 : *
510 : * Calls @c a.allocate(n)
511 : */
512 : [[__nodiscard__,__gnu__::__always_inline__]]
513 : static _GLIBCXX20_CONSTEXPR pointer
514 : allocate(allocator_type& __a, size_type __n)
515 : { return __a.allocate(__n); }
516 :
517 : /**
518 : * @brief Allocate memory.
519 : * @param __a An allocator.
520 : * @param __n The number of objects to allocate space for.
521 : * @param __hint Aid to locality.
522 : * @return Memory of suitable size and alignment for @a n objects
523 : * of type @c value_type
524 : *
525 : * Returns <tt> a.allocate(n, hint) </tt>
526 : */
527 : [[__nodiscard__,__gnu__::__always_inline__]]
528 : static _GLIBCXX20_CONSTEXPR pointer
529 : allocate(allocator_type& __a, size_type __n,
530 : [[maybe_unused]] const_void_pointer __hint)
531 : {
532 : #if __cplusplus <= 201703L
533 : return __a.allocate(__n, __hint);
534 : #else
535 : return __a.allocate(__n);
536 : #endif
537 : }
538 :
539 : /**
540 : * @brief Deallocate memory.
541 : * @param __a An allocator.
542 : * @param __p Pointer to the memory to deallocate.
543 : * @param __n The number of objects space was allocated for.
544 : *
545 : * Calls <tt> a.deallocate(p, n) </tt>
546 : */
547 : [[__gnu__::__always_inline__]]
548 : static _GLIBCXX20_CONSTEXPR void
549 : deallocate(allocator_type& __a, pointer __p, size_type __n)
550 0 : { __a.deallocate(__p, __n); }
551 :
552 : /**
553 : * @brief Construct an object of type `_Up`
554 : * @param __a An allocator.
555 : * @param __p Pointer to memory of suitable size and alignment for
556 : * an object of type `_Up`.
557 : * @param __args Constructor arguments.
558 : *
559 : * Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
560 : * in C++11, C++14 and C++17. Changed in C++20 to call
561 : * `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
562 : */
563 : template<typename _Up, typename... _Args>
564 : [[__gnu__::__always_inline__]]
565 : static _GLIBCXX20_CONSTEXPR void
566 : construct(allocator_type& __a __attribute__((__unused__)),
567 : _Up* __p, _Args&&... __args)
568 : #if __cplusplus <= 201703L
569 : noexcept(noexcept(__a.construct(__p, std::forward<_Args>(__args)...)))
570 : #else
571 : noexcept(__is_nothrow_new_constructible<_Up, _Args...>)
572 : #endif
573 : {
574 : #if __cplusplus <= 201703L
575 : __a.construct(__p, std::forward<_Args>(__args)...);
576 : #elif __cpp_constexpr_dynamic_alloc // >= C++20
577 : std::construct_at(__p, std::forward<_Args>(__args)...);
578 : #else
579 : std::_Construct(__p, std::forward<_Args>(__args)...);
580 : #endif
581 : }
582 :
583 : /**
584 : * @brief Destroy an object of type @a _Up
585 : * @param __a An allocator.
586 : * @param __p Pointer to the object to destroy
587 : *
588 : * Calls @c __a.destroy(__p).
589 : */
590 : template<typename _Up>
591 : [[__gnu__::__always_inline__]]
592 : static _GLIBCXX20_CONSTEXPR void
593 : destroy(allocator_type& __a __attribute__((__unused__)), _Up* __p)
594 : noexcept(is_nothrow_destructible<_Up>::value)
595 : {
596 : #if __cplusplus <= 201703L
597 : __a.destroy(__p);
598 : #else
599 : std::destroy_at(__p);
600 : #endif
601 0 : }
602 :
603 : /**
604 : * @brief The maximum supported allocation size
605 : * @param __a An allocator.
606 : * @return @c __a.max_size()
607 : */
608 : [[__gnu__::__always_inline__]]
609 : static _GLIBCXX20_CONSTEXPR size_type
610 : max_size(const allocator_type& __a __attribute__((__unused__))) noexcept
611 : {
612 : #if __cplusplus <= 201703L
613 : return __a.max_size();
614 : #else
615 : return size_t(-1) / sizeof(value_type);
616 : #endif
617 : }
618 :
619 : /**
620 : * @brief Obtain an allocator to use when copying a container.
621 : * @param __rhs An allocator.
622 : * @return @c __rhs
623 : */
624 : [[__gnu__::__always_inline__]]
625 : static _GLIBCXX20_CONSTEXPR allocator_type
626 : select_on_container_copy_construction(const allocator_type& __rhs)
627 : { return __rhs; }
628 : };
629 :
630 : /**
631 : * @brief Explicit specialization for `std::allocator<void>`
632 : * @headerfile memory
633 : * @ingroup allocators
634 : * @since C++11
635 : * @see std::allocator_traits
636 : */
637 : template<>
638 : struct allocator_traits<allocator<void>>
639 : {
640 : /// The allocator type
641 : using allocator_type = allocator<void>;
642 :
643 : /// The allocated type
644 : using value_type = void;
645 :
646 : /// The allocator's pointer type.
647 : using pointer = void*;
648 :
649 : /// The allocator's const pointer type.
650 : using const_pointer = const void*;
651 :
652 : /// The allocator's void pointer type.
653 : using void_pointer = void*;
654 :
655 : /// The allocator's const void pointer type.
656 : using const_void_pointer = const void*;
657 :
658 : /// The allocator's difference type
659 : using difference_type = std::ptrdiff_t;
660 :
661 : /// The allocator's size type
662 : using size_type = std::size_t;
663 :
664 : /// How the allocator is propagated on copy assignment
665 : using propagate_on_container_copy_assignment = false_type;
666 :
667 : /// How the allocator is propagated on move assignment
668 : using propagate_on_container_move_assignment = true_type;
669 :
670 : /// How the allocator is propagated on swap
671 : using propagate_on_container_swap = false_type;
672 :
673 : /// Whether all instances of the allocator type compare equal.
674 : using is_always_equal = true_type;
675 :
676 : template<typename _Up>
677 : using rebind_alloc = allocator<_Up>;
678 :
679 : template<typename _Up>
680 : using rebind_traits = allocator_traits<allocator<_Up>>;
681 :
682 : /// allocate is ill-formed for allocator<void>
683 : static void*
684 : allocate(allocator_type&, size_type, const void* = nullptr) = delete;
685 :
686 : /// deallocate is ill-formed for allocator<void>
687 : static void
688 : deallocate(allocator_type&, void*, size_type) = delete;
689 :
690 : /**
691 : * @brief Construct an object of type `_Up`
692 : * @param __a An allocator.
693 : * @param __p Pointer to memory of suitable size and alignment for
694 : * an object of type `_Up`.
695 : * @param __args Constructor arguments.
696 : *
697 : * Calls `__a.construct(__p, std::forward<_Args>(__args)...)`
698 : * in C++11, C++14 and C++17. Changed in C++20 to call
699 : * `std::construct_at(__p, std::forward<_Args>(__args)...)` instead.
700 : */
701 : template<typename _Up, typename... _Args>
702 : [[__gnu__::__always_inline__]]
703 : static _GLIBCXX20_CONSTEXPR void
704 : construct(allocator_type&, _Up* __p, _Args&&... __args)
705 : noexcept(__is_nothrow_new_constructible<_Up, _Args...>)
706 : { std::_Construct(__p, std::forward<_Args>(__args)...); }
707 :
708 : /**
709 : * @brief Destroy an object of type `_Up`
710 : * @param __a An allocator.
711 : * @param __p Pointer to the object to destroy
712 : *
713 : * Invokes the destructor for `*__p`.
714 : */
715 : template<typename _Up>
716 : [[__gnu__::__always_inline__]]
717 : static _GLIBCXX20_CONSTEXPR void
718 : destroy(allocator_type&, _Up* __p)
719 : noexcept(is_nothrow_destructible<_Up>::value)
720 : { std::_Destroy(__p); }
721 :
722 : /// max_size is ill-formed for allocator<void>
723 : static size_type
724 : max_size(const allocator_type&) = delete;
725 :
726 : /**
727 : * @brief Obtain an allocator to use when copying a container.
728 : * @param __rhs An allocator.
729 : * @return `__rhs`
730 : */
731 : [[__gnu__::__always_inline__]]
732 : static _GLIBCXX20_CONSTEXPR allocator_type
733 : select_on_container_copy_construction(const allocator_type& __rhs)
734 : { return __rhs; }
735 : };
736 : #endif
737 :
738 : /// @cond undocumented
739 : #if __cplusplus < 201703L
740 : template<typename _Alloc>
741 : [[__gnu__::__always_inline__]]
742 : inline void
743 : __do_alloc_on_copy(_Alloc& __one, const _Alloc& __two, true_type)
744 : { __one = __two; }
745 :
746 : template<typename _Alloc>
747 : [[__gnu__::__always_inline__]]
748 : inline void
749 : __do_alloc_on_copy(_Alloc&, const _Alloc&, false_type)
750 : { }
751 : #endif
752 :
753 : template<typename _Alloc>
754 : [[__gnu__::__always_inline__]]
755 : _GLIBCXX14_CONSTEXPR inline void
756 : __alloc_on_copy(_Alloc& __one, const _Alloc& __two)
757 : {
758 : using __traits = allocator_traits<_Alloc>;
759 : using __pocca =
760 : typename __traits::propagate_on_container_copy_assignment::type;
761 : #if __cplusplus >= 201703L
762 : if constexpr (__pocca::value)
763 : __one = __two;
764 : #else
765 : __do_alloc_on_copy(__one, __two, __pocca());
766 : #endif
767 : }
768 :
769 : template<typename _Alloc>
770 : [[__gnu__::__always_inline__]]
771 : constexpr _Alloc
772 : __alloc_on_copy(const _Alloc& __a)
773 : {
774 : typedef allocator_traits<_Alloc> __traits;
775 : return __traits::select_on_container_copy_construction(__a);
776 : }
777 :
778 : #if __cplusplus < 201703L
779 : template<typename _Alloc>
780 : [[__gnu__::__always_inline__]]
781 : inline void __do_alloc_on_move(_Alloc& __one, _Alloc& __two, true_type)
782 : { __one = std::move(__two); }
783 :
784 : template<typename _Alloc>
785 : [[__gnu__::__always_inline__]]
786 : inline void __do_alloc_on_move(_Alloc&, _Alloc&, false_type)
787 : { }
788 : #endif
789 :
790 : template<typename _Alloc>
791 : [[__gnu__::__always_inline__]]
792 : _GLIBCXX14_CONSTEXPR inline void
793 : __alloc_on_move(_Alloc& __one, _Alloc& __two)
794 : {
795 : using __traits = allocator_traits<_Alloc>;
796 : using __pocma
797 : = typename __traits::propagate_on_container_move_assignment::type;
798 : #if __cplusplus >= 201703L
799 : if constexpr (__pocma::value)
800 : __one = std::move(__two);
801 : #else
802 : __do_alloc_on_move(__one, __two, __pocma());
803 : #endif
804 : }
805 :
806 : #if __cplusplus < 201703L
807 : template<typename _Alloc>
808 : [[__gnu__::__always_inline__]]
809 : inline void __do_alloc_on_swap(_Alloc& __one, _Alloc& __two, true_type)
810 : {
811 : using std::swap;
812 : swap(__one, __two);
813 : }
814 :
815 : template<typename _Alloc>
816 : [[__gnu__::__always_inline__]]
817 : inline void __do_alloc_on_swap(_Alloc&, _Alloc&, false_type)
818 : { }
819 : #endif
820 :
821 : template<typename _Alloc>
822 : [[__gnu__::__always_inline__]]
823 : _GLIBCXX14_CONSTEXPR inline void
824 : __alloc_on_swap(_Alloc& __one, _Alloc& __two)
825 : {
826 : using __traits = allocator_traits<_Alloc>;
827 : using __pocs = typename __traits::propagate_on_container_swap::type;
828 : #if __cplusplus >= 201703L
829 : if constexpr (__pocs::value)
830 : {
831 : using std::swap;
832 : swap(__one, __two);
833 : }
834 : #else
835 : __do_alloc_on_swap(__one, __two, __pocs());
836 : #endif
837 : }
838 :
839 : template<typename _Alloc, typename _Tp,
840 : typename _ValueT = __remove_cvref_t<typename _Alloc::value_type>,
841 : typename = void>
842 : struct __is_alloc_insertable_impl
843 : : false_type
844 : { };
845 :
846 : template<typename _Alloc, typename _Tp, typename _ValueT>
847 : struct __is_alloc_insertable_impl<_Alloc, _Tp, _ValueT,
848 : __void_t<decltype(allocator_traits<_Alloc>::construct(
849 : std::declval<_Alloc&>(), std::declval<_ValueT*>(),
850 : std::declval<_Tp>()))>>
851 : : true_type
852 : { };
853 :
854 : // true if _Alloc::value_type is CopyInsertable into containers using _Alloc
855 : // (might be wrong if _Alloc::construct exists but is not constrained,
856 : // i.e. actually trying to use it would still be invalid. Use with caution.)
857 : template<typename _Alloc>
858 : struct __is_copy_insertable
859 : : __is_alloc_insertable_impl<_Alloc,
860 : typename _Alloc::value_type const&>::type
861 : { };
862 :
863 : #if _GLIBCXX_HOSTED
864 : // std::allocator<_Tp> just requires CopyConstructible
865 : template<typename _Tp>
866 : struct __is_copy_insertable<allocator<_Tp>>
867 : : is_copy_constructible<_Tp>
868 : { };
869 : #endif
870 :
871 : // true if _Alloc::value_type is MoveInsertable into containers using _Alloc
872 : // (might be wrong if _Alloc::construct exists but is not constrained,
873 : // i.e. actually trying to use it would still be invalid. Use with caution.)
874 : template<typename _Alloc>
875 : struct __is_move_insertable
876 : : __is_alloc_insertable_impl<_Alloc, typename _Alloc::value_type>::type
877 : { };
878 :
879 : #if _GLIBCXX_HOSTED
880 : // std::allocator<_Tp> just requires MoveConstructible
881 : template<typename _Tp>
882 : struct __is_move_insertable<allocator<_Tp>>
883 : : is_move_constructible<_Tp>
884 : { };
885 : #endif
886 :
887 : // Trait to detect Allocator-like types.
888 : template<typename _Alloc, typename = void>
889 : struct __is_allocator : false_type { };
890 :
891 : template<typename _Alloc>
892 : struct __is_allocator<_Alloc,
893 : __void_t<typename _Alloc::value_type,
894 : decltype(std::declval<_Alloc&>().allocate(size_t{}))>>
895 : : true_type { };
896 :
897 : template<typename _Alloc>
898 : using _RequireAllocator
899 : = typename enable_if<__is_allocator<_Alloc>::value, _Alloc>::type;
900 :
901 : template<typename _Alloc>
902 : using _RequireNotAllocator
903 : = typename enable_if<!__is_allocator<_Alloc>::value, _Alloc>::type;
904 :
905 : #if __cpp_concepts >= 201907L
906 : template<typename _Alloc>
907 : concept __allocator_like = requires (_Alloc& __a) {
908 : typename _Alloc::value_type;
909 : __a.deallocate(__a.allocate(1u), 1u);
910 : };
911 : #endif
912 : /// @endcond
913 : #endif // C++11
914 :
915 : /// @cond undocumented
916 :
917 : // To implement Option 3 of DR 431.
918 : template<typename _Alloc, bool = __is_empty(_Alloc)>
919 : struct __alloc_swap
920 : { static void _S_do_it(_Alloc&, _Alloc&) _GLIBCXX_NOEXCEPT { } };
921 :
922 : template<typename _Alloc>
923 : struct __alloc_swap<_Alloc, false>
924 : {
925 : static void
926 : _S_do_it(_Alloc& __one, _Alloc& __two) _GLIBCXX_NOEXCEPT
927 : {
928 : // Precondition: swappable allocators.
929 : if (__one != __two)
930 : swap(__one, __two);
931 : }
932 : };
933 :
934 : #if __cplusplus >= 201103L
935 : template<typename _Tp, bool
936 : = __or_<is_copy_constructible<typename _Tp::value_type>,
937 : is_nothrow_move_constructible<typename _Tp::value_type>>::value>
938 : struct __shrink_to_fit_aux
939 : { static bool _S_do_it(_Tp&) noexcept { return false; } };
940 :
941 : template<typename _Tp>
942 : struct __shrink_to_fit_aux<_Tp, true>
943 : {
944 : _GLIBCXX20_CONSTEXPR
945 : static bool
946 : _S_do_it(_Tp& __c) noexcept
947 : {
948 : #if __cpp_exceptions
949 : try
950 : {
951 : _Tp(__make_move_if_noexcept_iterator(__c.begin()),
952 : __make_move_if_noexcept_iterator(__c.end()),
953 : __c.get_allocator()).swap(__c);
954 : return true;
955 : }
956 : catch(...)
957 : { return false; }
958 : #else
959 : return false;
960 : #endif
961 : }
962 : };
963 : #endif
964 :
965 : /**
966 : * Destroy a range of objects using the supplied allocator. For
967 : * non-default allocators we do not optimize away invocation of
968 : * destroy() even if _Tp has a trivial destructor.
969 : */
970 :
971 : template<typename _ForwardIterator, typename _Allocator>
972 : _GLIBCXX20_CONSTEXPR
973 : void
974 : _Destroy(_ForwardIterator __first, _ForwardIterator __last,
975 : _Allocator& __alloc)
976 : {
977 : for (; __first != __last; ++__first)
978 : #if __cplusplus < 201103L
979 : __alloc.destroy(std::__addressof(*__first));
980 : #else
981 : allocator_traits<_Allocator>::destroy(__alloc,
982 : std::__addressof(*__first));
983 : #endif
984 : }
985 :
986 : #if _GLIBCXX_HOSTED
987 : template<typename _ForwardIterator, typename _Tp>
988 : __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR
989 : inline void
990 : _Destroy(_ForwardIterator __first, _ForwardIterator __last,
991 : allocator<_Tp>&)
992 : {
993 0 : std::_Destroy(__first, __last);
994 0 : }
995 : #endif
996 : /// @endcond
997 :
998 : _GLIBCXX_END_NAMESPACE_VERSION
999 : } // namespace std
1000 : #endif // _ALLOC_TRAITS_H
|