indirect.h
Go to the documentation of this file.
// 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 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(*__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(*__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 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
compare
initializer_list
allocator.h
functional_hash.h
allocated_ptr.h
utility.h
version.h
memory_resource.h
std::operator*
constexpr complex< _Tp > operator*(const complex< _Tp > &__x, const complex< _Tp > &__y)
Return new complex value x times y.
Definition complex:434
std::to_address
constexpr _Tp * to_address(_Tp *__ptr) noexcept
Obtain address referenced by a pointer to an object.
Definition ptr_traits.h:232
std::forward_like
constexpr __like_t< _Tp, _Up > forward_like(_Up &&__x) noexcept
Forward with the cv-qualifiers and value category of another type.
Definition move.h:125
std::move
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:138
std::__addressof
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition move.h:52
std::forward
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:72
std
ISO C++ entities toplevel namespace is std.
std::hash
Primary class template hash.
Definition functional_hash.h:106
std::__is_fast_hash
Definition functional_hash.h:308
alloc_traits.h