Commit 337d1fec by Ville Voutilainen Committed by Ville Voutilainen

Don't revisit a variant we are already visiting.

* include/std/variant (__variant_construct_single): New.
(__variant_construct): Use it.
(_M_destructive_move): Likewise.
(_M_destructive_copy): Likewise.
(_Copy_assign_base::operator=): Adjust.
(_Move_assign_base::operator=): Likewise.
(swap): Likewise.

From-SVN: r269996
parent c7a53bdb
2019-03-28 Ville Voutilainen <ville.voutilainen@gmail.com>
Don't revisit a variant we are already visiting.
* include/std/variant (__variant_construct_single): New.
(__variant_construct): Use it.
(_M_destructive_move): Likewise.
(_M_destructive_copy): Likewise.
(_Copy_assign_base::operator=): Adjust.
(_Move_assign_base::operator=): Likewise.
(swap): Likewise.
2019-03-26 Jonathan Wakely <jwakely@redhat.com> 2019-03-26 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/85965 PR libstdc++/85965
......
...@@ -428,20 +428,25 @@ namespace __variant ...@@ -428,20 +428,25 @@ namespace __variant
using _Variant_storage_alias = using _Variant_storage_alias =
_Variant_storage<_Traits<_Types...>::_S_trivial_dtor, _Types...>; _Variant_storage<_Traits<_Types...>::_S_trivial_dtor, _Types...>;
template<typename _Tp, typename _Up>
void __variant_construct_single(_Tp&& __lhs, _Up&& __rhs_mem)
{
void* __storage = std::addressof(__lhs._M_u);
using _Type = remove_reference_t<decltype(__rhs_mem)>;
if constexpr (!is_same_v<_Type, __variant_cookie>)
::new (__storage)
_Type(std::forward<decltype(__rhs_mem)>(__rhs_mem));
}
template<typename... _Types, typename _Tp, typename _Up> template<typename... _Types, typename _Tp, typename _Up>
void __variant_construct(_Tp&& __lhs, _Up&& __rhs) void __variant_construct(_Tp&& __lhs, _Up&& __rhs)
{ {
__lhs._M_index = __rhs._M_index; __lhs._M_index = __rhs._M_index;
void* __storage = std::addressof(__lhs._M_u); __do_visit([&__lhs](auto&& __rhs_mem) mutable
__do_visit([__storage](auto&& __rhs_mem) mutable
-> __detail::__variant::__variant_cookie -> __detail::__variant::__variant_cookie
{ {
using _Type = remove_reference_t<decltype(__rhs_mem)>; __variant_construct_single(std::forward<_Tp>(__lhs),
if constexpr (is_same_v<__remove_cvref_t<decltype(__rhs_mem)>, std::forward<decltype(__rhs_mem)>(__rhs_mem));
remove_cv_t<_Type>>
&& !is_same_v<_Type, __variant_cookie>)
::new (__storage)
_Type(std::forward<decltype(__rhs_mem)>(__rhs_mem));
return {}; return {};
}, __variant_cast<_Types...>(std::forward<decltype(__rhs)>(__rhs))); }, __variant_cast<_Types...>(std::forward<decltype(__rhs)>(__rhs)));
} }
...@@ -490,34 +495,38 @@ namespace __variant ...@@ -490,34 +495,38 @@ namespace __variant
std::forward<_Move_ctor_base>(__rhs)); std::forward<_Move_ctor_base>(__rhs));
} }
void _M_destructive_move(_Move_ctor_base&& __rhs) template<typename _Up>
{ void _M_destructive_move(unsigned short __rhs_index, _Up&& __rhs)
this->_M_reset(); {
__try this->_M_reset();
{ this->_M_index = __rhs_index;
__variant_construct<_Types...>(*this, __try
std::forward<_Move_ctor_base>(__rhs)); {
} __variant_construct_single(*this,
__catch (...) std::forward<_Up>(__rhs));
{ }
this->_M_index = variant_npos; __catch (...)
__throw_exception_again; {
} this->_M_index = variant_npos;
} __throw_exception_again;
}
}
void _M_destructive_copy(const _Move_ctor_base& __rhs) template<typename _Up>
{ void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs)
this->_M_reset(); {
__try this->_M_reset();
{ this->_M_index = __rhs_index;
__variant_construct<_Types...>(*this, __rhs); __try
} {
__catch (...) __variant_construct_single(*this, __rhs);
{ }
this->_M_index = variant_npos; __catch (...)
__throw_exception_again; {
} this->_M_index = variant_npos;
} __throw_exception_again;
}
}
_Move_ctor_base(const _Move_ctor_base&) = default; _Move_ctor_base(const _Move_ctor_base&) = default;
_Move_ctor_base& operator=(const _Move_ctor_base&) = default; _Move_ctor_base& operator=(const _Move_ctor_base&) = default;
...@@ -530,17 +539,21 @@ namespace __variant ...@@ -530,17 +539,21 @@ namespace __variant
using _Base = _Copy_ctor_alias<_Types...>; using _Base = _Copy_ctor_alias<_Types...>;
using _Base::_Base; using _Base::_Base;
void _M_destructive_move(_Move_ctor_base&& __rhs) template<typename _Up>
{ void _M_destructive_move(unsigned short __rhs_index, _Up&& __rhs)
this->_M_reset(); {
__variant_construct<_Types...>(*this, this->_M_reset();
std::forward<_Move_ctor_base>(__rhs)); this->_M_index = __rhs_index;
} __variant_construct_single(*this,
void _M_destructive_copy(const _Move_ctor_base& __rhs) std::forward<_Up>(__rhs));
{ }
this->_M_reset(); template<typename _Up>
__variant_construct<_Types...>(*this, __rhs); void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs)
} {
this->_M_reset();
this->_M_index = __rhs_index;
__variant_construct_single(*this, __rhs);
}
}; };
template<typename... _Types> template<typename... _Types>
...@@ -580,12 +593,13 @@ namespace __variant ...@@ -580,12 +593,13 @@ namespace __variant
if constexpr (is_nothrow_copy_constructible_v<__rhs_type> if constexpr (is_nothrow_copy_constructible_v<__rhs_type>
|| !is_nothrow_move_constructible_v<__rhs_type>) || !is_nothrow_move_constructible_v<__rhs_type>)
{ {
this->_M_destructive_copy(__rhs); this->_M_destructive_copy(__rhs._M_index, __rhs_mem);
} }
else else
{ {
_Copy_assign_base __tmp(__rhs); auto __tmp(__rhs_mem);
this->_M_destructive_move(std::move(__tmp)); this->_M_destructive_move(__rhs._M_index,
std::move(__tmp));
} }
} }
else else
...@@ -641,8 +655,8 @@ namespace __variant ...@@ -641,8 +655,8 @@ namespace __variant
} }
else else
{ {
_Move_assign_base __tmp(std::move(__rhs)); auto __tmp(std::move(__rhs_mem));
this->_M_destructive_move(std::move(__tmp)); this->_M_destructive_move(__rhs._M_index, std::move(__tmp));
} }
return {}; return {};
}, __variant_cast<_Types...>(*this), __variant_cast<_Types...>(__rhs)); }, __variant_cast<_Types...>(*this), __variant_cast<_Types...>(__rhs));
...@@ -1409,21 +1423,26 @@ namespace __variant ...@@ -1409,21 +1423,26 @@ namespace __variant
remove_reference_t<decltype(__this_mem)>, remove_reference_t<decltype(__this_mem)>,
__detail::__variant::__variant_cookie>) __detail::__variant::__variant_cookie>)
{ {
this->_M_destructive_move(std::move(__rhs)); this->_M_destructive_move(__rhs.index(),
std::move(__rhs_mem));
__rhs._M_reset(); __rhs._M_reset();
} }
else if constexpr (is_same_v< else if constexpr (is_same_v<
remove_reference_t<decltype(__rhs_mem)>, remove_reference_t<decltype(__rhs_mem)>,
__detail::__variant::__variant_cookie>) __detail::__variant::__variant_cookie>)
{ {
__rhs._M_destructive_move(std::move(*this)); __rhs._M_destructive_move(this->index(),
std::move(__this_mem));
this->_M_reset(); this->_M_reset();
} }
else else
{ {
auto __tmp = std::move(__rhs); auto __tmp(std::move(__rhs_mem));
__rhs._M_destructive_move(std::move(*this)); auto __idx = __rhs.index();
this->_M_destructive_move(std::move(__tmp)); __rhs._M_destructive_move(this->index(),
std::move(__this_mem));
this->_M_destructive_move(__idx,
std::move(__tmp));
} }
} }
return {}; return {};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment