These two changes both result in smaller code for std::variant.

The first one means smaller tables of function pointers, because we
don't generate an instantiation for the valueless state. Instead we do
a runtime branch, marked [[unlikely]] to make _M_reset() a no-op if
it's already valueless. In a microbenchmark I couldn't measure any
performance difference due to the extra branch, so the code size
reduction seems worthwhile.

The second one removes a branch from the index() member by relying on
unsigned arithmetic. That also results in smaller code and I can't see
any downside.

        * include/std/variant (_Variant_storage<false, _Types...>::_M_reset):
        Replace raw visitation with a runtime check for the valueless state
        and a non-raw visitor.
        (_Variant_storage<false, _Types...>::_M_reset_impl): Remove.
        (variant::index()): Remove branch.

Tested powerpc64le-linux, any objections?


commit a36ecd71f2e7ce95b479d4c06597f2ee0dfe27b1
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Wed May 15 22:33:31 2019 +0100

    Changes to std::variant to reduce code size
    
            * include/std/variant (_Variant_storage<false, 
_Types...>::_M_reset):
            Replace raw visitation with a runtime check for the valueless state
            and a non-raw visitor.
            (_Variant_storage<false, _Types...>::_M_reset_impl): Remove.
            (variant::index()): Remove branch.

diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index 8c710c30de5..8844c54913f 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -396,19 +396,16 @@ namespace __variant
        _M_index(_Np)
        { }
 
-      constexpr void _M_reset_impl()
-      {
-       __variant::__raw_visit([](auto&& __this_mem) mutable
-         {
-           if constexpr (!is_same_v<remove_reference_t<decltype(__this_mem)>,
-                         __variant_cookie>)
-             std::_Destroy(std::__addressof(__this_mem));
-         }, __variant_cast<_Types...>(*this));
-      }
-
       void _M_reset()
       {
-       _M_reset_impl();
+       if (!_M_valid()) [[unlikely]]
+         return;
+
+       std::__do_visit<void>([](auto&& __this_mem) mutable
+         {
+           std::_Destroy(std::__addressof(__this_mem));
+         }, __variant_cast<_Types...>(*this));
+
        _M_index = variant_npos;
       }
 
@@ -1485,12 +1482,7 @@ namespace __variant
       { return !this->_M_valid(); }
 
       constexpr size_t index() const noexcept
-      {
-       if (this->_M_index ==
-           typename _Base::__index_type(variant_npos))
-         return variant_npos;
-       return this->_M_index;
-      }
+      { return size_t(typename _Base::__index_type(this->_M_index + 1)) - 1; }
 
       void
       swap(variant& __rhs)

Reply via email to