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 
48 namespace 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 = std::move(__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 = std::move(__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 _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition: move.h:52
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition: move.h:138
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.
__detected_or_t< value_type *, __pointer, _Alloc > pointer
The allocator's pointer type.
typename _Ptr< __c_pointer, const value_type >::type const_pointer
The allocator's const pointer type.