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