libstdc++
indirect.h
Go to the documentation of this file.
1// Vocabulary Types for Composite Class Design -*- C++ -*-
2
3// Copyright The GNU Toolchain Authors.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file include/bits/indirect.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 _GLIBCXX_INDIRECT_H
31#define _GLIBCXX_INDIRECT_H 1
32
33#pragma GCC system_header
34
35#include <bits/version.h>
36
37#if __glibcxx_indirect || __glibcxx_polymorphic // >= C++26
38#include <compare>
39#include <initializer_list>
40#include <bits/allocator.h>
41#include <bits/alloc_traits.h>
42#include <bits/allocated_ptr.h> // __allocate_guarded
43#include <bits/uses_allocator.h> // allocator_arg_t
44#include <bits/utility.h> // __is_in_place_type_v
45#include <bits/functional_hash.h> // hash
46#include <bits/memory_resource.h> // polymorphic_allocator
47
48namespace std _GLIBCXX_VISIBILITY(default)
49{
50_GLIBCXX_BEGIN_NAMESPACE_VERSION
51
52#if __glibcxx_indirect
53 template<typename _Tp, typename _Alloc = allocator<_Tp>>
54 class indirect;
55
56 template<typename _Tp>
57 constexpr bool __is_indirect = false;
58 template<typename _Tp, typename _Alloc>
59 constexpr bool __is_indirect<indirect<_Tp, _Alloc>> = true;
60
61#if _GLIBCXX_HOSTED
62 namespace pmr
63 {
64 template<typename _Tp>
65 using indirect = indirect<_Tp, polymorphic_allocator<_Tp>>;
66 }
67#endif
68
69 // [indirect], class template indirect
70 template<typename _Tp, typename _Alloc>
71 class indirect
72 {
73 static_assert(is_object_v<_Tp>);
74 static_assert(!is_array_v<_Tp>);
75 static_assert(!is_same_v<_Tp, in_place_t>);
76 static_assert(!__is_in_place_type_v<_Tp>);
77 static_assert(!is_const_v<_Tp> && !is_volatile_v<_Tp>);
78
79 using _ATraits = allocator_traits<_Alloc>;
80 static_assert(is_same_v<_Tp, typename _ATraits::value_type>);
81
82 public:
83 using value_type = _Tp;
84 using allocator_type = _Alloc;
85 using pointer = typename allocator_traits<_Alloc>::pointer;
86 using const_pointer = typename allocator_traits<_Alloc>::const_pointer;
87
88 constexpr explicit
89 indirect() requires is_default_constructible_v<_Alloc>
90 : _M_objp(_M_make_obj_chk())
91 { }
92
93 constexpr explicit
94 indirect(allocator_arg_t, const _Alloc& __a)
95 : _M_alloc(__a), _M_objp(_M_make_obj_chk())
96 { }
97
98 constexpr
99 indirect(const indirect& __o)
100 : indirect(allocator_arg,
101 _ATraits::select_on_container_copy_construction(__o._M_alloc),
102 __o)
103 { }
104
105 constexpr
106 indirect(allocator_arg_t, const _Alloc& __a, const indirect& __other)
107 : _M_alloc(__a)
108 {
109 if (__other._M_objp)
110 _M_objp = _M_make_obj_chk(__other.__get());
111 else
112 _M_objp = nullptr;
113 }
114
115 constexpr
116 indirect(indirect&& __other) noexcept
117 : _M_alloc(std::move(__other._M_alloc)),
118 _M_objp(std::__exchange(__other._M_objp, nullptr))
119 { }
120
121 constexpr
122 indirect(allocator_arg_t, const _Alloc& __a,
123 indirect&& __other) noexcept(_ATraits::is_always_equal::value)
124 : _M_alloc(__a),
125 _M_objp(std::__exchange(__other._M_objp, nullptr))
126 {
127 if constexpr (!_ATraits::is_always_equal::value)
128 if (_M_objp && _M_alloc != __other._M_alloc)
129 {
130 static_assert(sizeof(_Tp) != 0, "must be a complete type");
131
132 // _M_alloc cannot free _M_objp, give it back to __other.
133 __other._M_objp = std::__exchange(_M_objp, nullptr);
134 // And create a new object that can be freed by _M_alloc.
135 _M_objp = _M_make_obj(std::move(*__other._M_objp));
136 }
137 }
138
139 template<typename _Up = _Tp>
140 requires (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
141 && (!is_same_v<remove_cvref_t<_Up>, indirect>)
142 && is_constructible_v<_Tp, _Up>
143 && is_default_constructible_v<_Alloc>
144 constexpr explicit
145 indirect(_Up&& __u)
146 : _M_objp(_M_make_obj(std::forward<_Up>(__u)))
147 { }
148
149 template<typename _Up = _Tp>
150 requires (!is_same_v<remove_cvref_t<_Up>, in_place_t>)
151 && (!is_same_v<remove_cvref_t<_Up>, indirect>)
152 && is_constructible_v<_Tp, _Up>
153 constexpr explicit
154 indirect(allocator_arg_t, const _Alloc& __a, _Up&& __u)
155 : _M_alloc(__a), _M_objp(_M_make_obj(std::forward<_Up>(__u)))
156 { }
157
158 template<typename... _Us>
159 requires is_constructible_v<_Tp, _Us...>
160 && is_default_constructible_v<_Alloc>
161 constexpr explicit
162 indirect(in_place_t, _Us&&... __us)
163 : _M_objp(_M_make_obj(std::forward<_Us>(__us)...))
164 { }
165
166 template<typename... _Us>
167 requires is_constructible_v<_Tp, _Us...>
168 constexpr explicit
169 indirect(allocator_arg_t, const _Alloc& __a, in_place_t, _Us&&... __us)
170 : _M_alloc(__a),
171 _M_objp(_M_make_obj(std::forward<_Us>(__us)...))
172 { }
173
174 template<typename _Ip, typename... _Us>
175 requires is_constructible_v<_Tp, initializer_list<_Ip>&, _Us...>
176 && is_default_constructible_v<_Alloc>
177 constexpr explicit
178 indirect(in_place_t, initializer_list<_Ip> __il, _Us&&... __us)
179 : _M_objp(_M_make_obj(__il, std::forward<_Us>(__us)...))
180 { }
181
182 template<typename _Ip, typename... _Us>
183 requires is_constructible_v<_Tp, initializer_list<_Ip>&, _Us...>
184 constexpr explicit
185 indirect(allocator_arg_t, const _Alloc& __a,
186 in_place_t, initializer_list<_Ip> __il, _Us&&... __us)
187 : _M_alloc(__a),
188 _M_objp(_M_make_obj(__il, std::forward<_Us>(__us)...))
189 { }
190
191 constexpr ~indirect()
192 {
193 static_assert(sizeof(_Tp) != 0, "must be a complete type");
194 _M_reset(nullptr);
195 }
196
197 constexpr indirect&
198 operator=(const indirect& __other)
199 {
200 static_assert(is_copy_assignable_v<_Tp>);
201 static_assert(is_copy_constructible_v<_Tp>);
202
203 if (__builtin_addressof(__other) == this) [[unlikely]]
204 return *this;
205
206 constexpr bool __pocca
207 = _ATraits::propagate_on_container_copy_assignment::value;
208
209 pointer __ptr = nullptr;
210 if (__other._M_objp)
211 {
212 if (_ATraits::is_always_equal::value
213 || _M_alloc == __other._M_alloc)
214 {
215 if (_M_objp)
216 {
217 *_M_objp = __other.__get();
218 if constexpr (__pocca)
219 _M_alloc = __other._M_alloc;
220 return *this;
221 }
222 }
223 const indirect& __x = __pocca ? __other : *this;
224 __ptr = __x._M_make_obj(__other.__get());
225 }
226
227 _M_reset(__ptr);
228
229 if constexpr (__pocca)
230 _M_alloc = __other._M_alloc;
231
232 return *this;
233 }
234
235 constexpr indirect&
236 operator=(indirect&& __other)
237 noexcept(_ATraits::propagate_on_container_move_assignment::value
238 || _ATraits::is_always_equal::value)
239 {
240 // N5008 says is_copy_constructible_v<T> here, but that seems wrong.
241 // We only require move-constructible, and only for unequal allocators.
242
243 if (__builtin_addressof(__other) == this) [[unlikely]]
244 return *this;
245
246 constexpr bool __pocma
247 = _ATraits::propagate_on_container_move_assignment::value;
248
249 pointer __ptr = nullptr;
250
251 // _GLIBCXX_RESOLVE_LIB_DEFECTS
252 // 4251. Move assignment for indirect unnecessarily requires copy construction
253 if constexpr (_ATraits::is_always_equal::value || __pocma)
254 __ptr = std::__exchange(__other._M_objp, nullptr);
255 else if (_M_alloc == __other._M_alloc)
256 __ptr = std::__exchange(__other._M_objp, nullptr);
257 else if (__other._M_objp)
258 {
259 static_assert(is_move_constructible_v<_Tp>);
260 __ptr = _M_make_obj(std::move(*__other._M_objp));
261 }
262
263 _M_reset(__ptr);
264
265 if constexpr (__pocma)
266 _M_alloc = __other._M_alloc;
267
268 return *this;
269 }
270
271 template<typename _Up = _Tp>
272 requires (!is_same_v<remove_cvref_t<_Up>, indirect>)
273 && is_constructible_v<_Tp, _Up> && is_assignable_v<_Tp&, _Up>
274 constexpr indirect&
275 operator=(_Up&& __u)
276 {
277 if (_M_objp == nullptr)
278 _M_objp = _M_make_obj(std::forward<_Up>(__u));
279 else
280 *_M_objp = std::forward<_Up>(__u);
281
282 return *this;
283 }
284
285 template<typename _Self>
286 constexpr auto&&
287 operator*(this _Self&& __self) noexcept
288 {
289 // n.b. [allocator.requirements.general] p22 implies
290 // dereferencing const pointer is same as pointer
291 const indirect& __iself = (const indirect&)__self;
292 __glibcxx_assert(__iself._M_objp != nullptr);
293 return std::forward_like<_Self>(*__iself._M_objp);
294 }
295
296 constexpr const_pointer
297 operator->() const noexcept
298 {
299 // Do we want to enforce this? __glibcxx_assert(_M_objp != nullptr);
300 return _M_objp;
301 }
302
303 constexpr pointer
304 operator->() noexcept
305 {
306 // Do we want to enforce this? __glibcxx_assert(_M_objp != nullptr);
307 return _M_objp;
308 }
309
310 constexpr bool
311 valueless_after_move() const noexcept { return _M_objp == nullptr; }
312
313 constexpr allocator_type
314 get_allocator() const noexcept { return _M_alloc; }
315
316 constexpr void
317 swap(indirect& __other)
318 noexcept(_ATraits::propagate_on_container_swap::value
319 || _ATraits::is_always_equal::value)
320 {
321 using std::swap;
322 swap(_M_objp, __other._M_objp);
323 if constexpr (_ATraits::propagate_on_container_swap::value)
324 swap(_M_alloc, __other._M_alloc);
325 else if constexpr (!_ATraits::is_always_equal::value)
326 __glibcxx_assert(_M_alloc == __other._M_alloc);
327 }
328
329 friend constexpr void
330 swap(indirect& __lhs, indirect& __rhs)
331 noexcept(_ATraits::propagate_on_container_swap::value
332 || _ATraits::is_always_equal::value)
333 { __lhs.swap(__rhs); }
334
335 template<typename _Up, typename _Alloc2>
336 requires requires (const _Tp& __t, const _Up& __u) { __t == __u; }
337 friend constexpr bool
338 operator==(const indirect& __lhs, const indirect<_Up, _Alloc2>& __rhs)
339 noexcept(noexcept(*__lhs == *__rhs))
340 {
341 if (!__lhs._M_objp || !__rhs._M_objp)
342 return bool(__lhs._M_objp) == bool(__rhs._M_objp);
343 else
344 return __lhs.__get() == __rhs.__get();
345 }
346
347 template<typename _Up>
348 requires (!__is_indirect<_Up>) // See PR c++/99599
349 && requires (const _Tp& __t, const _Up& __u) { __t == __u; }
350 friend constexpr bool
351 operator==(const indirect& __lhs, const _Up& __rhs)
352 noexcept(noexcept(*__lhs == __rhs))
353 {
354 if (!__lhs._M_objp)
355 return false;
356 else
357 return __lhs.__get() == __rhs;
358 }
359
360 template<typename _Up, typename _Alloc2>
361 friend constexpr __detail::__synth3way_t<_Tp, _Up>
362 operator<=>(const indirect& __lhs, const indirect<_Up, _Alloc2>& __rhs)
363 noexcept(noexcept(__detail::__synth3way(*__lhs, *__rhs)))
364 {
365 if (!__lhs._M_objp || !__rhs._M_objp)
366 return bool(__lhs._M_objp) <=> bool(__rhs._M_objp);
367 else
368 return __detail::__synth3way(__lhs.__get(), __rhs.__get());
369 }
370
371 template<typename _Up>
372 requires (!__is_indirect<_Up>) // See PR c++/99599
373 friend constexpr __detail::__synth3way_t<_Tp, _Up>
374 operator<=>(const indirect& __lhs, const _Up& __rhs)
375 noexcept(noexcept(__detail::__synth3way(*__lhs, __rhs)))
376 {
377 if (!__lhs._M_objp)
378 return strong_ordering::less;
379 else
380 return __detail::__synth3way(__lhs.__get(), __rhs);
381 }
382
383 private:
384 template<typename, typename> friend class indirect;
385
386 constexpr void
387 _M_reset(pointer __ptr) noexcept
388 {
389 if (_M_objp)
390 {
391 _ATraits::destroy(_M_alloc, std::to_address(_M_objp));
392 _ATraits::deallocate(_M_alloc, _M_objp, 1);
393 }
394 _M_objp = __ptr;
395 }
396
397 template<typename... _Args>
398 constexpr pointer
399 _M_make_obj(_Args&&... __args) const
400 {
401 _Scoped_allocation __sa(_M_alloc, in_place,
402 std::forward<_Args>(__args)...);
403 return __sa.release();
404 }
405
406 // Enforces is_constructible check and then calls _M_make_obj.
407 template<typename... _Args>
408 [[__gnu__::__always_inline__]]
409 constexpr pointer
410 _M_make_obj_chk(_Args&&... __args) const
411 {
412 static_assert(is_constructible_v<_Tp, _Args...>);
413 return _M_make_obj(std::forward<_Args>(__args)...);
414 }
415
416 // Always-const accessor that avoids ADL for operator*.
417 // This can be preferable to using *_M_objp because that might give _Tp&.
418 // This can be preferable to using **this because that does ADL.
419 [[__gnu__::__always_inline__]]
420 constexpr const _Tp&
421 __get() const noexcept
422 { return *_M_objp; }
423
424 [[no_unique_address]] _Alloc _M_alloc = _Alloc();
425 pointer _M_objp; // Pointer to the owned object.
426 };
427
428 template<typename _Value>
429 indirect(_Value) -> indirect<_Value>;
430
431 template<typename _Alloc, typename _Value>
432 indirect(allocator_arg_t, _Alloc, _Value)
433 -> indirect<_Value, __alloc_rebind<_Alloc, _Value>>;
434
435 // [indirect.hash], hash support
436 template<typename _Tp, typename _Alloc>
437 requires is_default_constructible_v<hash<_Tp>>
438 struct hash<indirect<_Tp, _Alloc>>
439 {
440 constexpr size_t
441 operator()(const indirect<_Tp, _Alloc>& __t) const
442 noexcept(noexcept(hash<_Tp>{}(*__t)))
443 {
444 // We pick an arbitrary hash for valueless indirect objects
445 // which hopefully usual values of _Tp won't typically hash to.
446 if (__t.valueless_after_move())
447 return -4444zu;
448 return hash<_Tp>{}(*__t);
449 }
450 };
451
452 template<typename _Tp, typename _Alloc>
453 struct __is_fast_hash<hash<indirect<_Tp, _Alloc>>>
454 : __is_fast_hash<hash<_Tp>>
455 { };
456#endif // __glibcxx_indirect
457
458#if __glibcxx_polymorphic // C++26 && HOSTED
459 template<typename _Tp, typename _Alloc = allocator<_Tp>>
460 class polymorphic;
461
462 namespace pmr
463 {
464 template<typename _Tp>
465 using polymorphic = polymorphic<_Tp, polymorphic_allocator<_Tp>>;
466 }
467
468 // [polymorphic], class template polymorphic
469 template<typename _Tp, typename _Alloc>
470 class polymorphic
471 {
472 static_assert(is_object_v<_Tp>);
473 static_assert(!is_array_v<_Tp>);
474 static_assert(!is_same_v<_Tp, in_place_t>);
475 static_assert(!__is_in_place_type_v<_Tp>);
476 static_assert(!is_const_v<_Tp> && !is_volatile_v<_Tp>);
477
478 using _ATraits = allocator_traits<_Alloc>;
479 static_assert(is_same_v<_Tp, typename _ATraits::value_type>);
480
481 // The owned object is embedded within a control block which knows the
482 // dynamic type and manages cloning and destroying the owned object.
483 struct _Obj
484 {
485 typename _ATraits::pointer _M_objp{}; // pointer to the owned object.
486
487 // A pointer to this type, e.g. _Obj*
488 using pointer
489 = typename _ATraits::template rebind_traits<_Obj>::pointer;
490
491 enum class _Op { _Dispose = 1, _Copy = 2, _Move = 3 };
492
493 constexpr virtual pointer
494 _M_manage(const _Alloc&, _Op, void* = nullptr) = 0;
495 };
496
497 template<typename _Up>
498 struct _Obj_impl : _Obj
499 {
500 using _MyTraits
501 = typename _ATraits::template rebind_traits<_Obj_impl>;
502
503 using _Op = _Obj::_Op;
504
505 union _Uninitialized {
506 constexpr _Uninitialized() { }
507 constexpr ~_Uninitialized() { }
508 _Up _M_objp;
509 };
510 _Uninitialized _M_u;
511
512 template<typename... _Args>
513 constexpr
514 _Obj_impl(typename _MyTraits::allocator_type& __a,
515 _Args&&... __args)
516 {
517 using _PtrTr = pointer_traits<typename _ATraits::pointer>;
518 _MyTraits::construct(__a, __builtin_addressof(_M_u._M_objp),
519 std::forward<_Args>(__args)...);
520 this->_M_objp = _PtrTr::pointer_to(_M_u._M_objp);
521 }
522
523 constexpr virtual typename _Obj::pointer
524 _M_manage(const _Alloc& __a, _Op __op, void*) override
525 {
526
527 switch (__op)
528 {
529 case _Op::_Move:
530 return _S_make_obj<_Up>(__a, std::move(_M_u._M_objp));
531 case _Op::_Copy:
532 return _S_make_obj<_Up>(__a,
533 const_cast<const _Up&>(_M_u._M_objp));
534 case _Op::_Dispose:
535 {
536 using _PtrTr = pointer_traits<typename _MyTraits::pointer>;
537 typename _MyTraits::allocator_type __a2(__a);
538 _MyTraits::destroy(__a2, std::__addressof(_M_u._M_objp));
539 _MyTraits::deallocate(__a2, _PtrTr::pointer_to(*this), 1);
540 return nullptr;
541 }
542 }
543 __builtin_unreachable();
544 }
545 };
546
547 // TODO: the standard permits a small-object optimization where the
548 // owned object is nested within the std::polymorphic not on the heap.
549
550 public:
551
552 using value_type = _Tp;
553 using allocator_type = _Alloc;
554 using pointer = typename allocator_traits<_Alloc>::pointer;
555 using const_pointer = typename allocator_traits<_Alloc>::const_pointer;
556
557 constexpr explicit
558 polymorphic() requires is_default_constructible_v<_Alloc>
559 : polymorphic(in_place_type<_Tp>)
560 { }
561
562 constexpr explicit
563 polymorphic(allocator_arg_t, const _Alloc& __a)
564 : polymorphic(allocator_arg, __a, in_place_type<_Tp>)
565 { }
566
567 constexpr
568 polymorphic(const polymorphic& __other)
569 : polymorphic(allocator_arg,
570 _ATraits::select_on_container_copy_construction(
571 __other._M_alloc),
572 __other)
573 { }
574
575 constexpr
576 polymorphic(allocator_arg_t, const _Alloc& __a,
577 const polymorphic& __other)
578 : _M_alloc(__a)
579 {
580 if (__other._M_objp)
581 _M_objp = __other._M_objp->_M_manage(__a, _Obj::_Op::_Copy);
582 else
583 _M_objp = nullptr;
584 }
585
586 constexpr
587 polymorphic(polymorphic&& __other) noexcept
588 : _M_alloc(std::move(__other._M_alloc)),
589 _M_objp(std::__exchange(__other._M_objp, nullptr))
590 { }
591
592 constexpr
593 polymorphic(allocator_arg_t, const _Alloc& __a, polymorphic&& __other)
594 noexcept(_ATraits::is_always_equal::value)
595 : _M_alloc(__a),
596 _M_objp(std::__exchange(__other._M_objp, nullptr))
597 {
598 if constexpr (!_ATraits::is_always_equal::value)
599 if (_M_objp && _M_alloc != __other._M_alloc)
600 {
601 // _M_alloc cannot free _M_objp, give it back to __other.
602 __other._M_objp = std::__exchange(_M_objp, nullptr);
603 // And create a new object that can be freed by _M_alloc.
604 _M_objp = __other._M_objp->_M_manage(__a, _Obj::_Op::_Move);
605 }
606 }
607
608 template<typename _Up = _Tp, typename _UUp = remove_cvref_t<_Up>>
609 requires (!is_same_v<_UUp, polymorphic>)
610 && (!__is_in_place_type_v<_UUp>)
611 && derived_from<_UUp, _Tp>
612 && is_constructible_v<_UUp, _Up>
613 && is_copy_constructible_v<_UUp>
614 && is_default_constructible_v<_Alloc>
615 constexpr explicit
616 polymorphic(_Up&& __u)
617 : _M_objp(_M_make_obj<_UUp>(std::forward<_Up>(__u)))
618 { }
619
620 template<typename _Up = _Tp, typename _UUp = remove_cvref_t<_Up>>
621 requires (!is_same_v<_UUp, polymorphic>)
622 && (!__is_in_place_type_v<_UUp>)
623 && derived_from<_UUp, _Tp>
624 && is_constructible_v<_UUp, _Up>
625 && is_copy_constructible_v<_UUp>
626 constexpr explicit
627 polymorphic(allocator_arg_t, const _Alloc& __a, _Up&& __u)
628 : _M_alloc(__a), _M_objp(_M_make_obj<_UUp>(std::forward<_Up>(__u)))
629 { }
630
631 template<typename _Up, typename... _Ts>
632 requires is_same_v<remove_cvref_t<_Up>, _Up>
633 && derived_from<_Up, _Tp>
634 && is_constructible_v<_Up, _Ts...>
635 && is_copy_constructible_v<_Up>
636 && is_default_constructible_v<_Alloc>
637 constexpr explicit
638 polymorphic(in_place_type_t<_Up> __t, _Ts&&... __ts)
639 : _M_objp(_M_make_obj<_Up>(std::forward<_Ts>(__ts)...))
640 { }
641
642 template<typename _Up, typename... _Ts>
643 requires is_same_v<remove_cvref_t<_Up>, _Up>
644 && derived_from<_Up, _Tp>
645 && is_constructible_v<_Up, _Ts...>
646 && is_copy_constructible_v<_Up>
647 constexpr explicit
648 polymorphic(allocator_arg_t, const _Alloc& __a,
649 in_place_type_t<_Up>, _Ts&&... __ts)
650 : _M_alloc(__a),
651 _M_objp(_M_make_obj<_Up>(std::forward<_Ts>(__ts)...))
652 { }
653
654 template<typename _Up, typename _Ip, typename... _Us>
655 requires is_same_v<remove_cvref_t<_Up>, _Up>
656 && derived_from<_Up, _Tp>
657 && is_constructible_v<_Up, initializer_list<_Ip>&, _Us...>
658 && is_copy_constructible_v<_Up>
659 && is_default_constructible_v<_Alloc>
660 constexpr explicit
661 polymorphic(in_place_type_t<_Up>, initializer_list<_Ip> __il,
662 _Us&&... __us)
663 : _M_objp(_M_make_obj<_Up>(__il, std::forward<_Us>(__us)...))
664 { }
665
666 template<typename _Up, typename _Ip, typename... _Us>
667 requires is_same_v<remove_cvref_t<_Up>, _Up>
668 && derived_from<_Up, _Tp>
669 && is_constructible_v<_Up, initializer_list<_Ip>&, _Us...>
670 && is_copy_constructible_v<_Up>
671 constexpr explicit
672 polymorphic(allocator_arg_t, const _Alloc& __a,
673 in_place_type_t<_Up>, initializer_list<_Ip> __il,
674 _Us&&... __us)
675 : _M_alloc(__a),
676 _M_objp(_M_make_obj<_Up>(__il, std::forward<_Us>(__us)...))
677 { }
678
679 constexpr ~polymorphic()
680 {
681 static_assert(sizeof(_Tp) != 0, "must be a complete type");
682 _M_reset(nullptr);
683 }
684
685 constexpr polymorphic&
686 operator=(const polymorphic& __other)
687 {
688 static_assert(sizeof(_Tp) != 0, "must be a complete type");
689
690 if (__builtin_addressof(__other) == this) [[unlikely]]
691 return *this;
692
693 constexpr bool __pocca
694 = _ATraits::propagate_on_container_copy_assignment::value;
695
696 typename _Obj::pointer __ptr = nullptr;
697 if (__other._M_objp)
698 {
699 auto& __a = __pocca ? __other._M_alloc : _M_alloc;
700 __ptr = __other._M_objp->_M_manage(__a, _Obj::_Op::_Copy);
701 }
702
703 _M_reset(__ptr);
704
705 if constexpr (__pocca)
706 _M_alloc = __other._M_alloc;
707
708 return *this;
709 }
710
711 constexpr polymorphic&
712 operator=(polymorphic&& __other)
713 noexcept(_ATraits::propagate_on_container_move_assignment::value
714 || _ATraits::is_always_equal::value)
715 {
716 if (__builtin_addressof(__other) == this) [[unlikely]]
717 return *this;
718
719 constexpr bool __pocma
720 = _ATraits::propagate_on_container_move_assignment::value;
721
722 typename _Obj::pointer __ptr = nullptr;
723
724 // _GLIBCXX_RESOLVE_LIB_DEFECTS
725 // 4251. Move assignment for indirect unnecessarily requires copy construction
726 if constexpr (_ATraits::is_always_equal::value || __pocma)
727 __ptr = std::__exchange(__other._M_objp, nullptr);
728 else if (_M_alloc == __other._M_alloc)
729 __ptr = std::__exchange(__other._M_objp, nullptr);
730 else if (__other._M_objp)
731 {
732 static_assert(sizeof(_Tp) != 0, "must be a complete type");
733 __ptr = __other._M_objp->_M_manage(_M_alloc, _Obj::_Op::_Move);
734 }
735
736 _M_reset(__ptr);
737
738 if constexpr (__pocma)
739 _M_alloc = __other._M_alloc;
740
741 return *this;
742 }
743
744 constexpr const _Tp&
745 operator*() const noexcept
746 {
747 __glibcxx_assert(_M_objp != nullptr);
748 return *_M_objp->_M_objp;
749 }
750
751 constexpr _Tp&
752 operator*() noexcept
753 {
754 __glibcxx_assert(_M_objp != nullptr);
755 return *_M_objp->_M_objp;
756 }
757
758 constexpr const_pointer
759 operator->() const noexcept
760 {
761 __glibcxx_assert(_M_objp != nullptr);
762 return _M_objp ? _M_objp->_M_objp : const_pointer{};
763 }
764
765 constexpr pointer
766 operator->() noexcept
767 {
768 __glibcxx_assert(_M_objp != nullptr);
769 return _M_objp ? _M_objp->_M_objp : pointer{};
770 }
771
772 constexpr bool
773 valueless_after_move() const noexcept { return _M_objp == nullptr; }
774
775 constexpr allocator_type
776 get_allocator() const noexcept { return _M_alloc; }
777
778 constexpr void
779 swap(polymorphic& __other)
780 noexcept(_ATraits::propagate_on_container_swap::value
781 || _ATraits::is_always_equal::value)
782 {
783 using std::swap;
784 swap(_M_objp, __other._M_objp);
785 if constexpr (_ATraits::propagate_on_container_swap::value)
786 swap(_M_alloc, __other._M_alloc);
787 else if constexpr (!_ATraits::is_always_equal::value)
788 __glibcxx_assert(_M_alloc == __other._M_alloc);
789 }
790
791 friend constexpr void
792 swap(polymorphic& __lhs, polymorphic& __rhs)
793 noexcept(_ATraits::propagate_on_container_swap::value
794 || _ATraits::is_always_equal::value)
795 { __lhs.swap(__rhs); }
796
797 private:
798 template<typename _Up, typename... _Args>
799 static constexpr typename _Obj::pointer
800 _S_make_obj(const _Alloc& __a, _Args&&... __args)
801 {
802 __alloc_rebind<_Alloc, _Obj_impl<_Up>> __objalloc(__a);
803 _Scoped_allocation __sa(__objalloc, in_place, __objalloc,
804 std::forward<_Args>(__args)...);
805 auto __obj = __sa.release();
806 // FIXME: We need to downcast from _Obj_impl<U>* to _Obj* but the
807 // the pointer_traits usage breaks in constexpr. PR c++/110714
808 if constexpr (is_pointer_v<typename _Obj::pointer>)
809 return __obj;
810 else
811 return pointer_traits<typename _Obj::pointer>::pointer_to(*__obj);
812 }
813
814 template<typename _Up, typename... _Args>
815 constexpr typename _Obj::pointer
816 _M_make_obj(_Args&&... __args) const
817 { return _S_make_obj<_Up>(_M_alloc, std::forward<_Args>(__args)...); }
818
819 constexpr void
820 _M_reset(typename _Obj::pointer __ptr) noexcept
821 {
822 if (_M_objp)
823 _M_objp->_M_manage(_M_alloc, _Obj::_Op::_Dispose);
824 _M_objp = __ptr;
825 }
826
827 [[no_unique_address]] _Alloc _M_alloc = _Alloc();
828 typename _Obj::pointer _M_objp;
829 };
830#endif // __glibcxx_polymorphic
831
832_GLIBCXX_END_NAMESPACE_VERSION
833} // namespace
834#endif // C++26 __glibcxx_indirect || __glibcxx_polymorphic
835
836#endif // _GLIBCXX_INDIRECT_H
constexpr complex< _Tp > operator*(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x times y.
Definition complex:434
constexpr _Tp * to_address(_Tp *__ptr) noexcept
Obtain address referenced by a pointer to an object.
Definition ptr_traits.h:232
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:138
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition move.h:52
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:72
ISO C++ entities toplevel namespace is std.
Primary class template hash.