| // Vocabulary Types for Composite Class Design -*- C++ -*- | |
| // Copyright The GNU Toolchain Authors. | |
| // | |
| // This file is part of the GNU ISO C++ Library. This library is free | |
| // software; you can redistribute it and/or modify it under the | |
| // terms of the GNU General Public License as published by the | |
| // Free Software Foundation; either version 3, or (at your option) | |
| // any later version. | |
| // This library is distributed in the hope that it will be useful, | |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| // GNU General Public License for more details. | |
| // Under Section 7 of GPL version 3, you are granted additional | |
| // permissions described in the GCC Runtime Library Exception, version | |
| // 3.1, as published by the Free Software Foundation. | |
| // You should have received a copy of the GNU General Public License and | |
| // a copy of the GCC Runtime Library Exception along with this program; | |
| // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
| // <http://www.gnu.org/licenses/>. | |
| /** @file include/bits/indirect.h | |
| * This is an internal header file, included by other library headers. | |
| * Do not attempt to use it directly. @headername{memory} | |
| */ | |
| #ifndef _GLIBCXX_INDIRECT_H | |
| #define _GLIBCXX_INDIRECT_H 1 | |
| #pragma GCC system_header | |
| #include <bits/version.h> | |
| #if __glibcxx_indirect || __glibcxx_polymorphic // >= C++26 | |
| #include <compare> | |
| #include <initializer_list> | |
| #include <bits/allocator.h> | |
| #include <bits/alloc_traits.h> | |
| #include <bits/allocated_ptr.h> // __allocate_guarded | |
| #include <bits/uses_allocator.h> // allocator_arg_t | |
| #include <bits/utility.h> // __is_in_place_type_v | |
| #include <bits/functional_hash.h> // hash | |
| #include <bits/memory_resource.h> // polymorphic_allocator | |
| namespace std _GLIBCXX_VISIBILITY(default) | |
| { | |
| _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
| #if __glibcxx_indirect | |
| template<typename _Tp, typename _Alloc = allocator<_Tp>> | |
| class indirect; | |
| template<typename _Tp> | |
| constexpr bool __is_indirect = false; | |
| template<typename _Tp, typename _Alloc> | |
| constexpr bool __is_indirect<indirect<_Tp, _Alloc>> = true; | |
| #if _GLIBCXX_HOSTED | |
| namespace pmr | |
| { | |
| template<typename _Tp> | |
| using indirect = indirect<_Tp, polymorphic_allocator<_Tp>>; | |
| } | |
| #endif | |
| // [indirect], class template indirect | |
| template<typename _Tp, typename _Alloc> | |
| class _GLIBCXX_NO_SPECIALIZATIONS indirect | |
| { | |
| static_assert(is_object_v<_Tp>); | |
| static_assert(!is_array_v<_Tp>); | |
| static_assert(!is_same_v<_Tp, in_place_t>); | |
| static_assert(!__is_in_place_type_v<_Tp>); | |
| static_assert(!is_const_v<_Tp> && !is_volatile_v<_Tp>); | |
| using _ATraits = allocator_traits<_Alloc>; | |
| static_assert(is_same_v<_Tp, typename _ATraits::value_type>); | |
| public: | |
| using value_type = _Tp; | |
| using allocator_type = _Alloc; | |
| using pointer = typename allocator_traits<_Alloc>::pointer; | |
| using const_pointer = typename allocator_traits<_Alloc>::const_pointer; | |
| constexpr explicit | |
| indirect() requires is_default_constructible_v<_Alloc> | |
| : _M_objp(_M_make_obj_chk()) | |
| { } | |
| constexpr explicit | |
| indirect(allocator_arg_t, const _Alloc& __a) | |
| : _M_alloc(__a), _M_objp(_M_make_obj_chk()) | |
| { } | |
| constexpr | |
| indirect(const indirect& __o) | |
| : indirect(allocator_arg, | |
| _ATraits::select_on_container_copy_construction(__o._M_alloc), | |
| __o) | |
| { } | |
| constexpr | |
| indirect(allocator_arg_t, const _Alloc& __a, const indirect& __other) | |
| : _M_alloc(__a) | |
| { | |
| if (__other._M_objp) | |
| _M_objp = _M_make_obj_chk(__other.__get()); | |
| else | |
| _M_objp = nullptr; | |
| } | |
| constexpr | |
| indirect(indirect&& __other) noexcept | |
| : _M_alloc(std::move(__other._M_alloc)), | |
| _M_objp(std::__exchange(__other._M_objp, nullptr)) | |
| { } | |
| constexpr | |
| indirect(allocator_arg_t, const _Alloc& __a, | |
| indirect&& __other) noexcept(_ATraits::is_always_equal::value) | |
| : _M_alloc(__a), | |
| _M_objp(std::__exchange(__other._M_objp, nullptr)) | |
| { | |
| if constexpr (!_ATraits::is_always_equal::value) | |
| if (_M_objp && _M_alloc != __other._M_alloc) | |
| { | |
| static_assert(sizeof(_Tp) != 0, "must be a complete type"); | |
| // _M_alloc cannot free _M_objp, give it back to __other. | |
| __other._M_objp = std::__exchange(_M_objp, nullptr); | |
| // And create a new object that can be freed by _M_alloc. | |
| _M_objp = _M_make_obj(std::move(*__other._M_objp)); | |
| } | |
| } | |
| template<typename _Up = _Tp> | |
| requires (!is_same_v<remove_cvref_t<_Up>, in_place_t>) | |
| && (!is_same_v<remove_cvref_t<_Up>, indirect>) | |
| && is_constructible_v<_Tp, _Up> | |
| && is_default_constructible_v<_Alloc> | |
| constexpr explicit | |
| indirect(_Up&& __u) | |
| : _M_objp(_M_make_obj(std::forward<_Up>(__u))) | |
| { } | |
| template<typename _Up = _Tp> | |
| requires (!is_same_v<remove_cvref_t<_Up>, in_place_t>) | |
| && (!is_same_v<remove_cvref_t<_Up>, indirect>) | |
| && is_constructible_v<_Tp, _Up> | |
| constexpr explicit | |
| indirect(allocator_arg_t, const _Alloc& __a, _Up&& __u) | |
| : _M_alloc(__a), _M_objp(_M_make_obj(std::forward<_Up>(__u))) | |
| { } | |
| template<typename... _Us> | |
| requires is_constructible_v<_Tp, _Us...> | |
| && is_default_constructible_v<_Alloc> | |
| constexpr explicit | |
| indirect(in_place_t, _Us&&... __us) | |
| : _M_objp(_M_make_obj(std::forward<_Us>(__us)...)) | |
| { } | |
| template<typename... _Us> | |
| requires is_constructible_v<_Tp, _Us...> | |
| constexpr explicit | |
| indirect(allocator_arg_t, const _Alloc& __a, in_place_t, _Us&&... __us) | |
| : _M_alloc(__a), | |
| _M_objp(_M_make_obj(std::forward<_Us>(__us)...)) | |
| { } | |
| template<typename _Ip, typename... _Us> | |
| requires is_constructible_v<_Tp, initializer_list<_Ip>&, _Us...> | |
| && is_default_constructible_v<_Alloc> | |
| constexpr explicit | |
| indirect(in_place_t, initializer_list<_Ip> __il, _Us&&... __us) | |
| : _M_objp(_M_make_obj(__il, std::forward<_Us>(__us)...)) | |
| { } | |
| template<typename _Ip, typename... _Us> | |
| requires is_constructible_v<_Tp, initializer_list<_Ip>&, _Us...> | |
| constexpr explicit | |
| indirect(allocator_arg_t, const _Alloc& __a, | |
| in_place_t, initializer_list<_Ip> __il, _Us&&... __us) | |
| : _M_alloc(__a), | |
| _M_objp(_M_make_obj(__il, std::forward<_Us>(__us)...)) | |
| { } | |
| constexpr ~indirect() | |
| { | |
| static_assert(sizeof(_Tp) != 0, "must be a complete type"); | |
| _M_reset(nullptr); | |
| } | |
| constexpr indirect& | |
| operator=(const indirect& __other) | |
| { | |
| static_assert(is_copy_assignable_v<_Tp>); | |
| static_assert(is_copy_constructible_v<_Tp>); | |
| if (__builtin_addressof(__other) == this) [[unlikely]] | |
| return *this; | |
| constexpr bool __pocca | |
| = _ATraits::propagate_on_container_copy_assignment::value; | |
| pointer __ptr = nullptr; | |
| if (__other._M_objp) | |
| { | |
| if (_ATraits::is_always_equal::value | |
| || _M_alloc == __other._M_alloc) | |
| { | |
| if (_M_objp) | |
| { | |
| *_M_objp = __other.__get(); | |
| if constexpr (__pocca) | |
| _M_alloc = __other._M_alloc; | |
| return *this; | |
| } | |
| } | |
| const indirect& __x = __pocca ? __other : *this; | |
| __ptr = __x._M_make_obj(__other.__get()); | |
| } | |
| _M_reset(__ptr); | |
| if constexpr (__pocca) | |
| _M_alloc = __other._M_alloc; | |
| return *this; | |
| } | |
| constexpr indirect& | |
| operator=(indirect&& __other) | |
| noexcept(_ATraits::propagate_on_container_move_assignment::value | |
| || _ATraits::is_always_equal::value) | |
| { | |
| // N5008 says is_copy_constructible_v<T> here, but that seems wrong. | |
| // We only require move-constructible, and only for unequal allocators. | |
| if (__builtin_addressof(__other) == this) [[unlikely]] | |
| return *this; | |
| constexpr bool __pocma | |
| = _ATraits::propagate_on_container_move_assignment::value; | |
| pointer __ptr = nullptr; | |
| // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
| // 4251. Move assignment for indirect unnecessarily requires copy construction | |
| if constexpr (_ATraits::is_always_equal::value || __pocma) | |
| __ptr = std::__exchange(__other._M_objp, nullptr); | |
| else if (_M_alloc == __other._M_alloc) | |
| __ptr = std::__exchange(__other._M_objp, nullptr); | |
| else if (__other._M_objp) | |
| { | |
| static_assert(is_move_constructible_v<_Tp>); | |
| __ptr = _M_make_obj(std::move(*__other._M_objp)); | |
| } | |
| _M_reset(__ptr); | |
| if constexpr (__pocma) | |
| _M_alloc = std::move(__other._M_alloc); | |
| return *this; | |
| } | |
| template<typename _Up = _Tp> | |
| requires (!is_same_v<remove_cvref_t<_Up>, indirect>) | |
| && is_constructible_v<_Tp, _Up> && is_assignable_v<_Tp&, _Up> | |
| constexpr indirect& | |
| operator=(_Up&& __u) | |
| { | |
| if (_M_objp == nullptr) | |
| _M_objp = _M_make_obj(std::forward<_Up>(__u)); | |
| else | |
| *_M_objp = std::forward<_Up>(__u); | |
| return *this; | |
| } | |
| template<typename _Self> | |
| constexpr auto&& | |
| operator*(this _Self&& __self) noexcept | |
| { | |
| // n.b. [allocator.requirements.general] p22 implies | |
| // dereferencing const pointer is same as pointer | |
| const indirect& __iself = (const indirect&)__self; | |
| __glibcxx_assert(__iself._M_objp != nullptr); | |
| return std::forward_like<_Self>(*__iself._M_objp); | |
| } | |
| constexpr const_pointer | |
| operator->() const noexcept | |
| { | |
| // Do we want to enforce this? __glibcxx_assert(_M_objp != nullptr); | |
| return _M_objp; | |
| } | |
| constexpr pointer | |
| operator->() noexcept | |
| { | |
| // Do we want to enforce this? __glibcxx_assert(_M_objp != nullptr); | |
| return _M_objp; | |
| } | |
| constexpr bool | |
| valueless_after_move() const noexcept { return _M_objp == nullptr; } | |
| constexpr allocator_type | |
| get_allocator() const noexcept { return _M_alloc; } | |
| constexpr void | |
| swap(indirect& __other) | |
| noexcept(_ATraits::propagate_on_container_swap::value | |
| || _ATraits::is_always_equal::value) | |
| { | |
| using std::swap; | |
| swap(_M_objp, __other._M_objp); | |
| if constexpr (_ATraits::propagate_on_container_swap::value) | |
| swap(_M_alloc, __other._M_alloc); | |
| else if constexpr (!_ATraits::is_always_equal::value) | |
| __glibcxx_assert(_M_alloc == __other._M_alloc); | |
| } | |
| friend constexpr void | |
| swap(indirect& __lhs, indirect& __rhs) | |
| noexcept(_ATraits::propagate_on_container_swap::value | |
| || _ATraits::is_always_equal::value) | |
| { __lhs.swap(__rhs); } | |
| template<typename _Up, typename _Alloc2> | |
| requires requires (const _Tp& __t, const _Up& __u) { __t == __u; } | |
| friend constexpr bool | |
| operator==(const indirect& __lhs, const indirect<_Up, _Alloc2>& __rhs) | |
| noexcept(noexcept(bool(*__lhs == *__rhs))) | |
| { | |
| if (!__lhs._M_objp || !__rhs._M_objp) | |
| return bool(__lhs._M_objp) == bool(__rhs._M_objp); | |
| else | |
| return __lhs.__get() == __rhs.__get(); | |
| } | |
| template<typename _Up, same_as<_Tp> _Vp> | |
| requires (!__is_indirect<_Up>) // See PR c++/99599 | |
| && requires (const _Tp& __t, const _Up& __u) { __t == __u; } | |
| friend constexpr bool | |
| operator==(const indirect<_Vp, _Alloc>& __lhs, const _Up& __rhs) | |
| noexcept(noexcept(bool(*__lhs == __rhs))) | |
| { | |
| if (!__lhs._M_objp) | |
| return false; | |
| else | |
| return __lhs.__get() == __rhs; | |
| } | |
| template<typename _Up, typename _Alloc2> | |
| friend constexpr __detail::__synth3way_t<_Tp, _Up> | |
| operator<=>(const indirect& __lhs, const indirect<_Up, _Alloc2>& __rhs) | |
| noexcept(noexcept(__detail::__synth3way(*__lhs, *__rhs))) | |
| { | |
| if (!__lhs._M_objp || !__rhs._M_objp) | |
| return bool(__lhs._M_objp) <=> bool(__rhs._M_objp); | |
| else | |
| return __detail::__synth3way(__lhs.__get(), __rhs.__get()); | |
| } | |
| template<typename _Up> | |
| requires (!__is_indirect<_Up>) // See PR c++/99599 | |
| friend constexpr __detail::__synth3way_t<_Tp, _Up> | |
| operator<=>(const indirect& __lhs, const _Up& __rhs) | |
| noexcept(noexcept(__detail::__synth3way(*__lhs, __rhs))) | |
| { | |
| if (!__lhs._M_objp) | |
| return strong_ordering::less; | |
| else | |
| return __detail::__synth3way(__lhs.__get(), __rhs); | |
| } | |
| private: | |
| template<typename, typename> friend class indirect; | |
| constexpr void | |
| _M_reset(pointer __ptr) noexcept | |
| { | |
| if (_M_objp) | |
| { | |
| _ATraits::destroy(_M_alloc, std::to_address(_M_objp)); | |
| _ATraits::deallocate(_M_alloc, _M_objp, 1); | |
| } | |
| _M_objp = __ptr; | |
| } | |
| template<typename... _Args> | |
| constexpr pointer | |
| _M_make_obj(_Args&&... __args) const | |
| { | |
| _Scoped_allocation __sa(_M_alloc, in_place, | |
| std::forward<_Args>(__args)...); | |
| return __sa.release(); | |
| } | |
| // Enforces is_constructible check and then calls _M_make_obj. | |
| template<typename... _Args> | |
| [[__gnu__::__always_inline__]] | |
| constexpr pointer | |
| _M_make_obj_chk(_Args&&... __args) const | |
| { | |
| static_assert(is_constructible_v<_Tp, _Args...>); | |
| return _M_make_obj(std::forward<_Args>(__args)...); | |
| } | |
| // Always-const accessor that avoids ADL for operator*. | |
| // This can be preferable to using *_M_objp because that might give _Tp&. | |
| // This can be preferable to using **this because that does ADL. | |
| [[__gnu__::__always_inline__]] | |
| constexpr const _Tp& | |
| __get() const noexcept | |
| { return *_M_objp; } | |
| [[no_unique_address]] _Alloc _M_alloc = _Alloc(); | |
| pointer _M_objp; // Pointer to the owned object. | |
| }; | |
| template<typename _Value> | |
| indirect(_Value) -> indirect<_Value>; | |
| template<typename _Alloc, typename _Value> | |
| indirect(allocator_arg_t, _Alloc, _Value) | |
| -> indirect<_Value, __alloc_rebind<_Alloc, _Value>>; | |
| // [indirect.hash], hash support | |
| template<typename _Tp, typename _Alloc> | |
| requires is_default_constructible_v<hash<_Tp>> | |
| struct hash<indirect<_Tp, _Alloc>> | |
| { | |
| constexpr size_t | |
| operator()(const indirect<_Tp, _Alloc>& __t) const | |
| noexcept(noexcept(hash<_Tp>{}(*__t))) | |
| { | |
| // We pick an arbitrary hash for valueless indirect objects | |
| // which hopefully usual values of _Tp won't typically hash to. | |
| if (__t.valueless_after_move()) | |
| return -4444zu; | |
| return hash<_Tp>{}(*__t); | |
| } | |
| }; | |
| template<typename _Tp, typename _Alloc> | |
| struct __is_fast_hash<hash<indirect<_Tp, _Alloc>>> | |
| : __is_fast_hash<hash<_Tp>> | |
| { }; | |
| #endif // __glibcxx_indirect | |
| #if __glibcxx_polymorphic // C++26 && HOSTED | |
| template<typename _Tp, typename _Alloc = allocator<_Tp>> | |
| class polymorphic; | |
| namespace pmr | |
| { | |
| template<typename _Tp> | |
| using polymorphic = polymorphic<_Tp, polymorphic_allocator<_Tp>>; | |
| } | |
| // [polymorphic], class template polymorphic | |
| template<typename _Tp, typename _Alloc> | |
| class _GLIBCXX_NO_SPECIALIZATIONS polymorphic | |
| { | |
| static_assert(is_object_v<_Tp>); | |
| static_assert(!is_array_v<_Tp>); | |
| static_assert(!is_same_v<_Tp, in_place_t>); | |
| static_assert(!__is_in_place_type_v<_Tp>); | |
| static_assert(!is_const_v<_Tp> && !is_volatile_v<_Tp>); | |
| using _ATraits = allocator_traits<_Alloc>; | |
| static_assert(is_same_v<_Tp, typename _ATraits::value_type>); | |
| // The owned object is embedded within a control block which knows the | |
| // dynamic type and manages cloning and destroying the owned object. | |
| struct _Obj | |
| { | |
| typename _ATraits::pointer _M_objp{}; // pointer to the owned object. | |
| // A pointer to this type, e.g. _Obj* | |
| using pointer | |
| = typename _ATraits::template rebind_traits<_Obj>::pointer; | |
| enum class _Op { _Dispose = 1, _Copy = 2, _Move = 3 }; | |
| constexpr virtual pointer | |
| _M_manage(const _Alloc&, _Op, void* = nullptr) = 0; | |
| }; | |
| template<typename _Up> | |
| struct _Obj_impl : _Obj | |
| { | |
| using _MyTraits | |
| = typename _ATraits::template rebind_traits<_Obj_impl>; | |
| using _Op = _Obj::_Op; | |
| union _Uninitialized { | |
| constexpr _Uninitialized() { } | |
| constexpr ~_Uninitialized() { } | |
| _Up _M_objp; | |
| }; | |
| _Uninitialized _M_u; | |
| template<typename... _Args> | |
| constexpr | |
| _Obj_impl(typename _MyTraits::allocator_type& __a, | |
| _Args&&... __args) | |
| { | |
| using _PtrTr = pointer_traits<typename _ATraits::pointer>; | |
| _MyTraits::construct(__a, __builtin_addressof(_M_u._M_objp), | |
| std::forward<_Args>(__args)...); | |
| this->_M_objp = _PtrTr::pointer_to(_M_u._M_objp); | |
| } | |
| constexpr virtual typename _Obj::pointer | |
| _M_manage(const _Alloc& __a, _Op __op, void*) override | |
| { | |
| switch (__op) | |
| { | |
| case _Op::_Move: | |
| return _S_make_obj<_Up>(__a, std::move(_M_u._M_objp)); | |
| case _Op::_Copy: | |
| return _S_make_obj<_Up>(__a, | |
| const_cast<const _Up&>(_M_u._M_objp)); | |
| case _Op::_Dispose: | |
| { | |
| using _PtrTr = pointer_traits<typename _MyTraits::pointer>; | |
| typename _MyTraits::allocator_type __a2(__a); | |
| _MyTraits::destroy(__a2, std::__addressof(_M_u._M_objp)); | |
| _MyTraits::deallocate(__a2, _PtrTr::pointer_to(*this), 1); | |
| return nullptr; | |
| } | |
| } | |
| __builtin_unreachable(); | |
| } | |
| }; | |
| // TODO: the standard permits a small-object optimization where the | |
| // owned object is nested within the std::polymorphic not on the heap. | |
| public: | |
| using value_type = _Tp; | |
| using allocator_type = _Alloc; | |
| using pointer = typename allocator_traits<_Alloc>::pointer; | |
| using const_pointer = typename allocator_traits<_Alloc>::const_pointer; | |
| constexpr explicit | |
| polymorphic() requires is_default_constructible_v<_Alloc> | |
| : polymorphic(in_place_type<_Tp>) | |
| { } | |
| constexpr explicit | |
| polymorphic(allocator_arg_t, const _Alloc& __a) | |
| : polymorphic(allocator_arg, __a, in_place_type<_Tp>) | |
| { } | |
| constexpr | |
| polymorphic(const polymorphic& __other) | |
| : polymorphic(allocator_arg, | |
| _ATraits::select_on_container_copy_construction( | |
| __other._M_alloc), | |
| __other) | |
| { } | |
| constexpr | |
| polymorphic(allocator_arg_t, const _Alloc& __a, | |
| const polymorphic& __other) | |
| : _M_alloc(__a) | |
| { | |
| if (__other._M_objp) | |
| _M_objp = __other._M_objp->_M_manage(__a, _Obj::_Op::_Copy); | |
| else | |
| _M_objp = nullptr; | |
| } | |
| constexpr | |
| polymorphic(polymorphic&& __other) noexcept | |
| : _M_alloc(std::move(__other._M_alloc)), | |
| _M_objp(std::__exchange(__other._M_objp, nullptr)) | |
| { } | |
| constexpr | |
| polymorphic(allocator_arg_t, const _Alloc& __a, polymorphic&& __other) | |
| noexcept(_ATraits::is_always_equal::value) | |
| : _M_alloc(__a), | |
| _M_objp(std::__exchange(__other._M_objp, nullptr)) | |
| { | |
| if constexpr (!_ATraits::is_always_equal::value) | |
| if (_M_objp && _M_alloc != __other._M_alloc) | |
| { | |
| // _M_alloc cannot free _M_objp, give it back to __other. | |
| __other._M_objp = std::__exchange(_M_objp, nullptr); | |
| // And create a new object that can be freed by _M_alloc. | |
| _M_objp = __other._M_objp->_M_manage(__a, _Obj::_Op::_Move); | |
| } | |
| } | |
| template<typename _Up = _Tp, typename _UUp = remove_cvref_t<_Up>> | |
| requires (!is_same_v<_UUp, polymorphic>) | |
| && (!__is_in_place_type_v<_UUp>) | |
| && derived_from<_UUp, _Tp> | |
| && is_constructible_v<_UUp, _Up> | |
| && is_copy_constructible_v<_UUp> | |
| && is_default_constructible_v<_Alloc> | |
| constexpr explicit | |
| polymorphic(_Up&& __u) | |
| : _M_objp(_M_make_obj<_UUp>(std::forward<_Up>(__u))) | |
| { } | |
| template<typename _Up = _Tp, typename _UUp = remove_cvref_t<_Up>> | |
| requires (!is_same_v<_UUp, polymorphic>) | |
| && (!__is_in_place_type_v<_UUp>) | |
| && derived_from<_UUp, _Tp> | |
| && is_constructible_v<_UUp, _Up> | |
| && is_copy_constructible_v<_UUp> | |
| constexpr explicit | |
| polymorphic(allocator_arg_t, const _Alloc& __a, _Up&& __u) | |
| : _M_alloc(__a), _M_objp(_M_make_obj<_UUp>(std::forward<_Up>(__u))) | |
| { } | |
| template<typename _Up, typename... _Ts> | |
| requires is_same_v<remove_cvref_t<_Up>, _Up> | |
| && derived_from<_Up, _Tp> | |
| && is_constructible_v<_Up, _Ts...> | |
| && is_copy_constructible_v<_Up> | |
| && is_default_constructible_v<_Alloc> | |
| constexpr explicit | |
| polymorphic(in_place_type_t<_Up> __t, _Ts&&... __ts) | |
| : _M_objp(_M_make_obj<_Up>(std::forward<_Ts>(__ts)...)) | |
| { } | |
| template<typename _Up, typename... _Ts> | |
| requires is_same_v<remove_cvref_t<_Up>, _Up> | |
| && derived_from<_Up, _Tp> | |
| && is_constructible_v<_Up, _Ts...> | |
| && is_copy_constructible_v<_Up> | |
| constexpr explicit | |
| polymorphic(allocator_arg_t, const _Alloc& __a, | |
| in_place_type_t<_Up>, _Ts&&... __ts) | |
| : _M_alloc(__a), | |
| _M_objp(_M_make_obj<_Up>(std::forward<_Ts>(__ts)...)) | |
| { } | |
| template<typename _Up, typename _Ip, typename... _Us> | |
| requires is_same_v<remove_cvref_t<_Up>, _Up> | |
| && derived_from<_Up, _Tp> | |
| && is_constructible_v<_Up, initializer_list<_Ip>&, _Us...> | |
| && is_copy_constructible_v<_Up> | |
| && is_default_constructible_v<_Alloc> | |
| constexpr explicit | |
| polymorphic(in_place_type_t<_Up>, initializer_list<_Ip> __il, | |
| _Us&&... __us) | |
| : _M_objp(_M_make_obj<_Up>(__il, std::forward<_Us>(__us)...)) | |
| { } | |
| template<typename _Up, typename _Ip, typename... _Us> | |
| requires is_same_v<remove_cvref_t<_Up>, _Up> | |
| && derived_from<_Up, _Tp> | |
| && is_constructible_v<_Up, initializer_list<_Ip>&, _Us...> | |
| && is_copy_constructible_v<_Up> | |
| constexpr explicit | |
| polymorphic(allocator_arg_t, const _Alloc& __a, | |
| in_place_type_t<_Up>, initializer_list<_Ip> __il, | |
| _Us&&... __us) | |
| : _M_alloc(__a), | |
| _M_objp(_M_make_obj<_Up>(__il, std::forward<_Us>(__us)...)) | |
| { } | |
| constexpr ~polymorphic() | |
| { | |
| static_assert(sizeof(_Tp) != 0, "must be a complete type"); | |
| _M_reset(nullptr); | |
| } | |
| constexpr polymorphic& | |
| operator=(const polymorphic& __other) | |
| { | |
| static_assert(sizeof(_Tp) != 0, "must be a complete type"); | |
| if (__builtin_addressof(__other) == this) [[unlikely]] | |
| return *this; | |
| constexpr bool __pocca | |
| = _ATraits::propagate_on_container_copy_assignment::value; | |
| typename _Obj::pointer __ptr = nullptr; | |
| if (__other._M_objp) | |
| { | |
| auto& __a = __pocca ? __other._M_alloc : _M_alloc; | |
| __ptr = __other._M_objp->_M_manage(__a, _Obj::_Op::_Copy); | |
| } | |
| _M_reset(__ptr); | |
| if constexpr (__pocca) | |
| _M_alloc = __other._M_alloc; | |
| return *this; | |
| } | |
| constexpr polymorphic& | |
| operator=(polymorphic&& __other) | |
| noexcept(_ATraits::propagate_on_container_move_assignment::value | |
| || _ATraits::is_always_equal::value) | |
| { | |
| if (__builtin_addressof(__other) == this) [[unlikely]] | |
| return *this; | |
| constexpr bool __pocma | |
| = _ATraits::propagate_on_container_move_assignment::value; | |
| typename _Obj::pointer __ptr = nullptr; | |
| // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
| // 4251. Move assignment for indirect unnecessarily requires copy construction | |
| if constexpr (_ATraits::is_always_equal::value || __pocma) | |
| __ptr = std::__exchange(__other._M_objp, nullptr); | |
| else if (_M_alloc == __other._M_alloc) | |
| __ptr = std::__exchange(__other._M_objp, nullptr); | |
| else if (__other._M_objp) | |
| { | |
| static_assert(sizeof(_Tp) != 0, "must be a complete type"); | |
| __ptr = __other._M_objp->_M_manage(_M_alloc, _Obj::_Op::_Move); | |
| } | |
| _M_reset(__ptr); | |
| if constexpr (__pocma) | |
| _M_alloc = std::move(__other._M_alloc); | |
| return *this; | |
| } | |
| constexpr const _Tp& | |
| operator*() const noexcept | |
| { | |
| __glibcxx_assert(_M_objp != nullptr); | |
| return *_M_objp->_M_objp; | |
| } | |
| constexpr _Tp& | |
| operator*() noexcept | |
| { | |
| __glibcxx_assert(_M_objp != nullptr); | |
| return *_M_objp->_M_objp; | |
| } | |
| constexpr const_pointer | |
| operator->() const noexcept | |
| { | |
| __glibcxx_assert(_M_objp != nullptr); | |
| return _M_objp ? _M_objp->_M_objp : const_pointer{}; | |
| } | |
| constexpr pointer | |
| operator->() noexcept | |
| { | |
| __glibcxx_assert(_M_objp != nullptr); | |
| return _M_objp ? _M_objp->_M_objp : pointer{}; | |
| } | |
| constexpr bool | |
| valueless_after_move() const noexcept { return _M_objp == nullptr; } | |
| constexpr allocator_type | |
| get_allocator() const noexcept { return _M_alloc; } | |
| constexpr void | |
| swap(polymorphic& __other) | |
| noexcept(_ATraits::propagate_on_container_swap::value | |
| || _ATraits::is_always_equal::value) | |
| { | |
| using std::swap; | |
| swap(_M_objp, __other._M_objp); | |
| if constexpr (_ATraits::propagate_on_container_swap::value) | |
| swap(_M_alloc, __other._M_alloc); | |
| else if constexpr (!_ATraits::is_always_equal::value) | |
| __glibcxx_assert(_M_alloc == __other._M_alloc); | |
| } | |
| friend constexpr void | |
| swap(polymorphic& __lhs, polymorphic& __rhs) | |
| noexcept(_ATraits::propagate_on_container_swap::value | |
| || _ATraits::is_always_equal::value) | |
| { __lhs.swap(__rhs); } | |
| private: | |
| template<typename _Up, typename... _Args> | |
| static constexpr typename _Obj::pointer | |
| _S_make_obj(const _Alloc& __a, _Args&&... __args) | |
| { | |
| __alloc_rebind<_Alloc, _Obj_impl<_Up>> __objalloc(__a); | |
| _Scoped_allocation __sa(__objalloc, in_place, __objalloc, | |
| std::forward<_Args>(__args)...); | |
| auto __obj = __sa.release(); | |
| // FIXME: We need to downcast from _Obj_impl<U>* to _Obj* but the | |
| // the pointer_traits usage breaks in constexpr. PR c++/110714 | |
| if constexpr (is_pointer_v<typename _Obj::pointer>) | |
| return __obj; | |
| else | |
| return pointer_traits<typename _Obj::pointer>::pointer_to(*__obj); | |
| } | |
| template<typename _Up, typename... _Args> | |
| constexpr typename _Obj::pointer | |
| _M_make_obj(_Args&&... __args) const | |
| { return _S_make_obj<_Up>(_M_alloc, std::forward<_Args>(__args)...); } | |
| constexpr void | |
| _M_reset(typename _Obj::pointer __ptr) noexcept | |
| { | |
| if (_M_objp) | |
| _M_objp->_M_manage(_M_alloc, _Obj::_Op::_Dispose); | |
| _M_objp = __ptr; | |
| } | |
| [[no_unique_address]] _Alloc _M_alloc = _Alloc(); | |
| typename _Obj::pointer _M_objp; | |
| }; | |
| #endif // __glibcxx_polymorphic | |
| _GLIBCXX_END_NAMESPACE_VERSION | |
| } // namespace | |
| #endif // C++26 __glibcxx_indirect || __glibcxx_polymorphic | |
| #endif // _GLIBCXX_INDIRECT_H |