From f1ba6c5a51936ac9065789b1fdb77f4e35f90efd Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Mon, 1 Apr 2019 16:57:41 +0300 Subject: [PATCH] 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 --- libstdc++-v3/ChangeLog | 19 +++ libstdc++-v3/include/std/variant | 219 +++++++++++++++++-------------- 2 files changed, 141 insertions(+), 97 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 98c218b5f7e..0b3d0c2d7e8 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,22 @@ +2019-04-01 Ville Voutilainen + + 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 * src/c++17/fs_ops.cc (fs::permissions): Use std::errc::not_supported. diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index 7fd694714ad..a7cc2065073 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -138,7 +138,7 @@ namespace __variant constexpr variant_alternative_t<_Np, variant<_Types...>> const&& get(const variant<_Types...>&&); - template + template 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{}; // _Uninitialized 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, - remove_reference_t>) + if constexpr (__rhs_index != variant_npos) { - if constexpr (!is_same_v< - remove_reference_t, - __variant_cookie>) - __this_mem = __rhs_mem; - } - else - { - if constexpr (!is_same_v< - remove_reference_t, - __variant_cookie>) + if (this->_M_index == __rhs_index) { - using __rhs_type = - remove_reference_t; - 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); + auto& __this_mem = + __variant::__get<__rhs_index>(*this); + if constexpr (is_same_v< + remove_reference_t, + remove_reference_t>) + __this_mem = __rhs_mem; } + } + else + { + using __rhs_type = + remove_reference_t; + 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._M_index, + this->_M_destructive_move(__rhs_index, std::move(__tmp)); } } - else - { - this->_M_reset(); - } } - 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, - remove_reference_t>) + if constexpr (__rhs_index != variant_npos) { - if constexpr (!is_same_v< - remove_reference_t, - __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, + remove_reference_t>) + __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()...); + 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, \ - remove_reference_t> \ - || is_same_v) \ - __ret = (__lhs.index() + 1) __OP (__rhs.index() + 1); \ - else if constexpr (is_same_v< \ - remove_reference_t, \ - remove_reference_t> \ - && !is_same_v< \ - remove_reference_t, \ - __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) { - __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, - remove_reference_t>) + if constexpr (__rhs_index != variant_npos) { - if constexpr (!is_same_v< - remove_reference_t, - __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, - __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, - __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 + template + 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 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; -- 2.30.2