Use single-visitation in variant assignment and swap and relops.

Also use indices instead of types when checking whether
variants hold the same thing.
* include/std/variant (__do_visit): Add a template parameter
for index visitation, invoke with indices if index visitation
is used.
(__variant_idx_cookie): New.
(__visit_with_index): Likewise.
(_Copy_assign_base::operator=): Do single-visitation with
an index visitor.
(_Move_assign_base::operator=): Likewise.
(_Extra_visit_slot_needed): Adjust.
(__visit_invoke): Call with indices if it's an index visitor.
(relops): Do single-visitation with an index visitor.
(swap): Likewise.
(__visitor_result_type): New.

From-SVN: r270056
This commit is contained in:
Ville Voutilainen 2019-04-01 16:57:41 +03:00 committed by Ville Voutilainen
parent e37240b0b5
commit f1ba6c5a51
2 changed files with 143 additions and 99 deletions

View File

@ -1,3 +1,22 @@
2019-04-01 Ville Voutilainen <ville.voutilainen@gmail.com>
Use single-visitation in variant assignment and swap and relops.
Also use indices instead of types when checking whether
variants hold the same thing.
* include/std/variant (__do_visit): Add a template parameter
for index visitation, invoke with indices if index visitation
is used.
(__variant_idx_cookie): New.
(__visit_with_index): Likewise.
(_Copy_assign_base::operator=): Do single-visitation with
an index visitor.
(_Move_assign_base::operator=): Likewise.
(_Extra_visit_slot_needed): Adjust.
(__visit_invoke): Call with indices if it's an index visitor.
(relops): Do single-visitation with an index visitor.
(swap): Likewise.
(__visitor_result_type): New.
2019-03-30 Eric Botcazou <ebotcazou@adacore.com>
* src/c++17/fs_ops.cc (fs::permissions): Use std::errc::not_supported.

View File

@ -138,7 +138,7 @@ namespace __variant
constexpr variant_alternative_t<_Np, variant<_Types...>> const&&
get(const variant<_Types...>&&);
template<typename _Visitor, typename... _Variants>
template<bool __use_index=false, typename _Visitor, typename... _Variants>
constexpr decltype(auto)
__do_visit(_Visitor&& __visitor, _Variants&&... __variants);
@ -175,6 +175,10 @@ namespace __variant
// used for raw visitation
struct __variant_cookie {};
// used for raw visitation with indices passed in
struct __variant_idx_cookie {};
// a more explanatory name than 'true'
inline constexpr auto __visit_with_index = bool_constant<true>{};
// _Uninitialized<T> is guaranteed to be a literal type, even if T is not.
// We have to do this, because [basic.types]p10.5.3 (n4606) is not implemented
@ -570,45 +574,44 @@ namespace __variant
operator=(const _Copy_assign_base& __rhs)
noexcept(_Traits<_Types...>::_S_nothrow_copy_assign)
{
__do_visit([this, &__rhs](auto&& __this_mem, auto&& __rhs_mem) mutable
-> __detail::__variant::__variant_cookie
__do_visit<__visit_with_index>([this](auto&& __rhs_mem,
auto __rhs_index) mutable
-> __detail::__variant::__variant_idx_cookie
{
if constexpr (is_same_v<
remove_reference_t<decltype(__this_mem)>,
remove_reference_t<decltype(__rhs_mem)>>)
if constexpr (__rhs_index != variant_npos)
{
if constexpr (!is_same_v<
remove_reference_t<decltype(__rhs_mem)>,
__variant_cookie>)
__this_mem = __rhs_mem;
}
else
{
if constexpr (!is_same_v<
remove_reference_t<decltype(__rhs_mem)>,
__variant_cookie>)
if (this->_M_index == __rhs_index)
{
using __rhs_type =
remove_reference_t<decltype(__rhs_mem)>;
if constexpr (is_nothrow_copy_constructible_v<__rhs_type>
|| !is_nothrow_move_constructible_v<__rhs_type>)
if constexpr (__rhs_index != variant_npos)
{
this->_M_destructive_copy(__rhs._M_index, __rhs_mem);
}
else
{
auto __tmp(__rhs_mem);
this->_M_destructive_move(__rhs._M_index,
std::move(__tmp));
auto& __this_mem =
__variant::__get<__rhs_index>(*this);
if constexpr (is_same_v<
remove_reference_t<decltype(__this_mem)>,
remove_reference_t<decltype(__rhs_mem)>>)
__this_mem = __rhs_mem;
}
}
else
{
this->_M_reset();
using __rhs_type =
remove_reference_t<decltype(__rhs_mem)>;
if constexpr
(is_nothrow_copy_constructible_v<__rhs_type>
|| !is_nothrow_move_constructible_v<__rhs_type>)
this->_M_destructive_copy(__rhs_index, __rhs_mem);
else
{
auto __tmp(__rhs_mem);
this->_M_destructive_move(__rhs_index,
std::move(__tmp));
}
}
}
return {};
}, __variant_cast<_Types...>(*this), __variant_cast<_Types...>(__rhs));
else
this->_M_reset();
return {};
}, __variant_cast<_Types...>(__rhs));
__glibcxx_assert(this->_M_index == __rhs._M_index);
return *this;
}
@ -641,25 +644,32 @@ namespace __variant
operator=(_Move_assign_base&& __rhs)
noexcept(_Traits<_Types...>::_S_nothrow_move_assign)
{
__do_visit([this, &__rhs](auto&& __this_mem, auto&& __rhs_mem) mutable
-> __detail::__variant::__variant_cookie
__do_visit<__visit_with_index>([this](auto&& __rhs_mem,
auto __rhs_index) mutable
-> __detail::__variant::__variant_idx_cookie
{
if constexpr (is_same_v<
remove_reference_t<decltype(__this_mem)>,
remove_reference_t<decltype(__rhs_mem)>>)
if constexpr (__rhs_index != variant_npos)
{
if constexpr (!is_same_v<
remove_reference_t<decltype(__rhs_mem)>,
__variant_cookie>)
__this_mem = std::move(__rhs_mem);
if (this->_M_index == __rhs_index)
{
if constexpr (__rhs_index != variant_npos)
{
auto& __this_mem =
__variant::__get<__rhs_index>(*this);
if constexpr (is_same_v<
remove_reference_t<decltype(__this_mem)>,
remove_reference_t<decltype(__rhs_mem)>>)
__this_mem = std::move(__rhs_mem);
}
}
else
this->_M_destructive_move(__rhs_index,
std::move(__rhs_mem));
}
else
{
auto __tmp(std::move(__rhs_mem));
this->_M_destructive_move(__rhs._M_index, std::move(__tmp));
}
return {};
}, __variant_cast<_Types...>(*this), __variant_cast<_Types...>(__rhs));
this->_M_reset();
return {};
}, __variant_cast<_Types...>(__rhs));
__glibcxx_assert(this->_M_index == __rhs._M_index);
return *this;
}
@ -777,7 +787,8 @@ namespace __variant
: bool_constant<__never_valueless<_Types...>()> {};
static constexpr bool value =
is_same_v<_Maybe_variant_cookie, __variant_cookie>
(is_same_v<_Maybe_variant_cookie, __variant_cookie>
|| is_same_v<_Maybe_variant_cookie, __variant_idx_cookie>)
&& !_Variant_never_valueless<__remove_cvref_t<_Variant>>::value;
};
@ -925,7 +936,13 @@ namespace __variant
static constexpr decltype(auto)
__visit_invoke(_Visitor&& __visitor, _Variants... __vars)
{
return std::__invoke(std::forward<_Visitor>(__visitor),
if constexpr (is_same_v<_Result_type, __variant_idx_cookie>)
return std::__invoke(std::forward<_Visitor>(__visitor),
__element_by_index_or_cookie<__indices>(
std::forward<_Variants>(__vars))...,
integral_constant<size_t, __indices>()...);
else
return std::__invoke(std::forward<_Visitor>(__visitor),
__element_by_index_or_cookie<__indices>(
std::forward<_Variants>(__vars))...);
}
@ -1082,25 +1099,25 @@ namespace __variant
const variant<_Types...>& __rhs) \
{ \
bool __ret = true; \
__do_visit([&__ret, &__lhs, __rhs] \
(auto&& __this_mem, auto&& __rhs_mem) mutable \
-> __detail::__variant::__variant_cookie \
__do_visit<__detail::__variant::__visit_with_index>( \
[&__ret, &__lhs, __rhs] \
(auto&& __rhs_mem, auto __rhs_index) mutable \
-> __detail::__variant::__variant_idx_cookie \
{ \
if constexpr (!is_same_v< \
remove_reference_t<decltype(__this_mem)>, \
remove_reference_t<decltype(__rhs_mem)>> \
|| is_same_v<decltype(__this_mem), \
__detail::__variant::__variant_cookie>) \
__ret = (__lhs.index() + 1) __OP (__rhs.index() + 1); \
else if constexpr (is_same_v< \
remove_reference_t<decltype(__this_mem)>, \
remove_reference_t<decltype(__rhs_mem)>> \
&& !is_same_v< \
remove_reference_t<decltype(__this_mem)>, \
__detail::__variant::__variant_cookie>) \
__ret = __this_mem __OP __rhs_mem; \
if constexpr (__rhs_index != variant_npos) \
{ \
if (__lhs.index() == __rhs_index) \
{ \
auto& __this_mem = std::get<__rhs_index>(__lhs); \
__ret = __this_mem __OP __rhs_mem; \
} \
else \
__ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \
} \
else \
__ret = (__lhs.index() + 1) __OP (__rhs_index + 1); \
return {}; \
}, __lhs, __rhs); \
}, __rhs); \
return __ret; \
} \
\
@ -1402,51 +1419,47 @@ namespace __variant
noexcept((__is_nothrow_swappable<_Types>::value && ...)
&& is_nothrow_move_constructible_v<variant>)
{
__do_visit([this, &__rhs](auto&& __this_mem, auto&& __rhs_mem) mutable
-> __detail::__variant::__variant_cookie
__do_visit<__detail::__variant::__visit_with_index>(
[this, &__rhs](auto&& __rhs_mem,
auto __rhs_index) mutable
-> __detail::__variant::__variant_idx_cookie
{
if constexpr (is_same_v<
remove_reference_t<decltype(__this_mem)>,
remove_reference_t<decltype(__rhs_mem)>>)
if constexpr (__rhs_index != variant_npos)
{
if constexpr (!is_same_v<
remove_reference_t<decltype(__rhs_mem)>,
__detail::__variant::__variant_cookie>)
if (this->index() == __rhs_index)
{
auto& __this_mem =
std::get<__rhs_index>(*this);
using std::swap;
swap(__this_mem, __rhs_mem);
}
else
{
if (this->index() != variant_npos)
{
auto __tmp(std::move(__rhs_mem));
__rhs = std::move(*this);
this->_M_destructive_move(__rhs_index,
std::move(__tmp));
}
else
{
this->_M_destructive_move(__rhs_index,
std::move(__rhs_mem));
__rhs._M_reset();
}
}
}
else
{
if constexpr (is_same_v<
remove_reference_t<decltype(__this_mem)>,
__detail::__variant::__variant_cookie>)
if (this->index() != variant_npos)
{
this->_M_destructive_move(__rhs.index(),
std::move(__rhs_mem));
__rhs._M_reset();
}
else if constexpr (is_same_v<
remove_reference_t<decltype(__rhs_mem)>,
__detail::__variant::__variant_cookie>)
{
__rhs._M_destructive_move(this->index(),
std::move(__this_mem));
__rhs = std::move(*this);
this->_M_reset();
}
else
{
auto __tmp(std::move(__rhs_mem));
auto __idx = __rhs.index();
__rhs._M_destructive_move(this->index(),
std::move(__this_mem));
this->_M_destructive_move(__idx,
std::move(__tmp));
}
}
return {};
}, *this, __rhs);
return {};
}, __rhs);
}
private:
@ -1523,13 +1536,25 @@ namespace __variant
return __detail::__variant::__get<_Np>(std::move(__v));
}
template<typename _Visitor, typename... _Variants>
template<bool __use_index, typename _Visitor, typename... _Variants>
decltype(auto)
__visitor_result_type(_Visitor&& __visitor, _Variants&&... __variants)
{
if constexpr(__use_index)
return __detail::__variant::__variant_idx_cookie{};
else
return std::forward<_Visitor>(__visitor)(
std::get<0>(std::forward<_Variants>(__variants))...);
}
template<bool __use_index, typename _Visitor, typename... _Variants>
constexpr decltype(auto)
__do_visit(_Visitor&& __visitor, _Variants&&... __variants)
{
using _Result_type =
decltype(std::forward<_Visitor>(__visitor)(
std::get<0>(std::forward<_Variants>(__variants))...));
decltype(__visitor_result_type<__use_index>(
std::forward<_Visitor>(__visitor),
std::forward<_Variants>(__variants)...));
constexpr auto& __vtable = __detail::__variant::__gen_vtable<
_Result_type, _Visitor&&, _Variants&&...>::_S_vtable;