From 453b00dec880de85cec0c39567092a83e2c79b98 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 13 Jan 2021 02:10:12 +0200 Subject: [PATCH] Use (i+1)*2+j for the internal index in the double-buffered case, to avoid branches --- include/boost/variant2/variant.hpp | 235 +++++++++++++++-------------- 1 file changed, 121 insertions(+), 114 deletions(-) diff --git a/include/boost/variant2/variant.hpp b/include/boost/variant2/variant.hpp index 7a4a2cf..d526dab 100644 --- a/include/boost/variant2/variant.hpp +++ b/include/boost/variant2/variant.hpp @@ -520,11 +520,11 @@ template union variant_storage_impl rest_; - template constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward(a)... ) + template constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward(a)... ) { } - template constexpr explicit variant_storage_impl( mp11::mp_size_t, A&&... a ): rest_( mp11::mp_size_t(), std::forward(a)... ) + template constexpr variant_storage_impl( mp11::mp_size_t, A&&... a ): rest_( mp11::mp_size_t(), std::forward(a)... ) { } @@ -564,18 +564,18 @@ template rest_; - template constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t, A&&... a ): rest_( mp11::mp_size_t(), std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t, A&&... a ): rest_( mp11::mp_size_t(), std::forward(a)... ) {} ~variant_storage_impl() { @@ -637,11 +637,11 @@ template union variant_storage_impl rest_; - template constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward(a)... ) + template constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): first_( std::forward(a)... ) { } - template constexpr explicit variant_storage_impl( mp11::mp_size_t, A&&... a ): rest_( mp11::mp_size_t(), std::forward(a)... ) + template constexpr variant_storage_impl( mp11::mp_size_t, A&&... a ): rest_( mp11::mp_size_t(), std::forward(a)... ) { } @@ -687,18 +687,18 @@ template rest_; - template constexpr explicit variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<0>, A&&... a ): t0_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<1>, A&&... a ): t1_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<2>, A&&... a ): t2_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<3>, A&&... a ): t3_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<4>, A&&... a ): t4_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<5>, A&&... a ): t5_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<6>, A&&... a ): t6_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<7>, A&&... a ): t7_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<8>, A&&... a ): t8_( std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t<9>, A&&... a ): t9_( std::forward(a)... ) {} - template constexpr explicit variant_storage_impl( mp11::mp_size_t, A&&... a ): rest_( mp11::mp_size_t(), std::forward(a)... ) {} + template constexpr variant_storage_impl( mp11::mp_size_t, A&&... a ): rest_( mp11::mp_size_t(), std::forward(a)... ) {} template void emplace_impl( mp11::mp_false, mp11::mp_size_t<0>, A&&... a ) { ::new( &t0_ ) T0( std::forward(a)... ); } template void emplace_impl( mp11::mp_false, mp11::mp_size_t<1>, A&&... a ) { ::new( &t1_ ) T1( std::forward(a)... ); } @@ -814,27 +814,27 @@ struct none {}; // trivially destructible, single buffered template struct variant_base_impl { - int ix_; - variant_storage st1_; + unsigned ix_; + variant_storage st_; - constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() ) + constexpr variant_base_impl(): ix_( 0 ), st_( mp11::mp_size_t<0>() ) { } - template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t(), std::forward(a)... ) + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st_( mp11::mp_size_t(), std::forward(a)... ) { } // requires: ix_ == 0 template void _replace( I, A&&... a ) { - ::new( &st1_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + ::new( &st_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); ix_ = I::value + 1; } constexpr std::size_t index() const noexcept { - return ix_ - 1; + return static_cast( ix_ ) - 1; } template BOOST_CXX14_CONSTEXPR mp11::mp_at_c, I>& _get_impl( mp11::mp_size_t ) noexcept @@ -843,7 +843,7 @@ template struct variant_base_impl assert( ix_ == J ); - return st1_.get( mp11::mp_size_t() ); + return st_.get( mp11::mp_size_t() ); } template constexpr mp11::mp_at_c, I> const& _get_impl( mp11::mp_size_t ) const noexcept @@ -851,14 +851,14 @@ template struct variant_base_impl // size_t const J = I+1; // assert( ix_ == I+1 ); - return st1_.get( mp11::mp_size_t() ); + return st_.get( mp11::mp_size_t() ); } template BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_true, A&&... a ) { static_assert( std::is_nothrow_constructible::value, "Logic error: U must be nothrow constructible from A&&..." ); - st1_.emplace( mp11::mp_size_t(), std::forward(a)... ); + st_.emplace( mp11::mp_size_t(), std::forward(a)... ); ix_ = J; } @@ -868,7 +868,7 @@ template struct variant_base_impl U tmp( std::forward(a)... ); - st1_.emplace( mp11::mp_size_t(), std::move(tmp) ); + st_.emplace( mp11::mp_size_t(), std::move(tmp) ); ix_ = J; } @@ -884,84 +884,78 @@ template struct variant_base_impl // trivially destructible, double buffered template struct variant_base_impl { - int ix_; - variant_storage st1_; - variant_storage st2_; + unsigned ix_; + variant_storage st_[ 2 ]; - constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() ), st2_( mp11::mp_size_t<0>() ) + constexpr variant_base_impl(): ix_( 0 ), st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } } { } - template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t(), std::forward(a)... ), st2_( mp11::mp_size_t<0>() ) + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st_{ { mp11::mp_size_t(), std::forward(a)... }, { mp11::mp_size_t<0>() } } { } // requires: ix_ == 0 template void _replace( I, A&&... a ) { - ::new( &st1_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); - ix_ = I::value + 1; + ::new( &st_[ 0 ] ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + ix_ = ( I::value + 1 ) * 2; } constexpr std::size_t index() const noexcept { - return ix_ >= 0? ix_ - 1: -ix_ - 1; + return static_cast( ix_ ) / 2 - 1; } template BOOST_CXX14_CONSTEXPR mp11::mp_at_c, I>& _get_impl( mp11::mp_size_t ) noexcept { + assert( index() == I ); + size_t const J = I+1; - assert( ix_ == J || -ix_ == J ); - constexpr mp11::mp_size_t j{}; - return ix_ >= 0? st1_.get( j ): st2_.get( j ); + return st_[ ix_ & 1 ].get( j ); } template constexpr mp11::mp_at_c, I> const& _get_impl( mp11::mp_size_t ) const noexcept { + // assert( index() == I ); // size_t const J = I+1; - // assert( ix_ == J || -ix_ == J ); // constexpr mp_size_t j{}; - return ix_ >= 0? st1_.get( mp11::mp_size_t() ): st2_.get( mp11::mp_size_t() ); + return st_[ ix_ & 1 ].get( mp11::mp_size_t() ); } template BOOST_CXX14_CONSTEXPR void emplace( A&&... a ) { size_t const J = I+1; - if( ix_ >= 0 ) - { - st2_.emplace( mp11::mp_size_t(), std::forward(a)... ); - ix_ = -static_cast( J ); - } - else - { - st1_.emplace( mp11::mp_size_t(), std::forward(a)... ); - ix_ = J; - } + unsigned i2 = 1 - ( ix_ & 1 ); + + st_[ i2 ].emplace( mp11::mp_size_t(), std::forward(a)... ); + + ix_ = J * 2 + i2; } }; // not trivially destructible, single buffered template struct variant_base_impl { - int ix_; - variant_storage st1_; + unsigned ix_; + variant_storage st_; - constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() ) + constexpr variant_base_impl(): ix_( 0 ), st_( mp11::mp_size_t<0>() ) { } - template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t(), std::forward(a)... ) + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st_( mp11::mp_size_t(), std::forward(a)... ) { } // requires: ix_ == 0 template void _replace( I, A&&... a ) { - ::new( &st1_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + ::new( &st_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); ix_ = I::value + 1; } @@ -977,7 +971,7 @@ template struct variant_base_impl template void operator()( I ) const noexcept { using U = mp11::mp_at, I>; - this_->st1_.get( I() ).~U(); + this_->st_.get( I() ).~U(); } }; @@ -996,7 +990,7 @@ template struct variant_base_impl constexpr std::size_t index() const noexcept { - return ix_ - 1; + return static_cast( ix_ ) - 1; } template BOOST_CXX14_CONSTEXPR mp11::mp_at_c, I>& _get_impl( mp11::mp_size_t ) noexcept @@ -1005,7 +999,7 @@ template struct variant_base_impl assert( ix_ == J ); - return st1_.get( mp11::mp_size_t() ); + return st_.get( mp11::mp_size_t() ); } template constexpr mp11::mp_at_c, I> const& _get_impl( mp11::mp_size_t ) const noexcept @@ -1013,7 +1007,7 @@ template struct variant_base_impl // size_t const J = I+1; // assert( ix_ == J ); - return st1_.get( mp11::mp_size_t() ); + return st_.get( mp11::mp_size_t() ); } template void emplace( A&&... a ) @@ -1028,7 +1022,7 @@ template struct variant_base_impl _destroy(); - st1_.emplace( mp11::mp_size_t(), std::move(tmp) ); + st_.emplace( mp11::mp_size_t(), std::move(tmp) ); ix_ = J; } }; @@ -1036,23 +1030,61 @@ template struct variant_base_impl // not trivially destructible, double buffered template struct variant_base_impl { - int ix_; - variant_storage st1_; - variant_storage st2_; + unsigned ix_; + +#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) + + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63707 :-( + + variant_storage st1_, st2_; constexpr variant_base_impl(): ix_( 0 ), st1_( mp11::mp_size_t<0>() ), st2_( mp11::mp_size_t<0>() ) { } - template constexpr explicit variant_base_impl( I, A&&... a ): ix_( I::value + 1 ), st1_( mp11::mp_size_t(), std::forward(a)... ), st2_( mp11::mp_size_t<0>() ) + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st1_( mp11::mp_size_t(), std::forward(a)... ), st2_( mp11::mp_size_t<0>() ) { } + BOOST_CXX14_CONSTEXPR variant_storage& storage( unsigned i2 ) noexcept + { + return i2 == 0? st1_: st2_; + } + + constexpr variant_storage const& storage( unsigned i2 ) const noexcept + { + return i2 == 0? st1_: st2_; + } + +#else + + variant_storage st_[ 2 ]; + + constexpr variant_base_impl(): ix_( 0 ), st_{ { mp11::mp_size_t<0>() }, { mp11::mp_size_t<0>() } } + { + } + + template constexpr explicit variant_base_impl( I, A&&... a ): ix_( ( I::value + 1 ) * 2 ), st_{ { mp11::mp_size_t(), std::forward(a)... }, { mp11::mp_size_t<0>() } } + { + } + + BOOST_CXX14_CONSTEXPR variant_storage& storage( unsigned i2 ) noexcept + { + return st_[ i2 ]; + } + + constexpr variant_storage const& storage( unsigned i2 ) const noexcept + { + return st_[ i2 ]; + } + +#endif + // requires: ix_ == 0 template void _replace( I, A&&... a ) { - ::new( &st1_ ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); - ix_ = I::value + 1; + ::new( &storage( 0 ) ) variant_storage( mp11::mp_size_t(), std::forward(a)... ); + ix_ = ( I::value + 1 ) * 2; } //[&]( auto I ){ @@ -1063,35 +1095,18 @@ template struct variant_base_impl struct _destroy_L1 { variant_base_impl * this_; + unsigned i2_; template void operator()( I ) const noexcept { using U = mp11::mp_at, I>; - this_->st1_.get( I() ).~U(); - } - }; - - struct _destroy_L2 - { - variant_base_impl * this_; - - template void operator()( I ) const noexcept - { - using U = mp11::mp_at, I>; - this_->st2_.get( I() ).~U(); + this_->storage( i2_ ).get( I() ).~U(); } }; void _destroy() noexcept { - if( ix_ > 0 ) - { - mp11::mp_with_index<1 + sizeof...(T)>( ix_, _destroy_L1{ this } ); - } - else if( ix_ < 0 ) - { - mp11::mp_with_index<1 + sizeof...(T)>( -ix_, _destroy_L2{ this } ); - } + mp11::mp_with_index<1 + sizeof...(T)>( ix_ / 2, _destroy_L1{ this, ix_ & 1 } ); } ~variant_base_impl() noexcept @@ -1101,46 +1116,38 @@ template struct variant_base_impl constexpr std::size_t index() const noexcept { - return ix_ >= 0? ix_ - 1: -ix_ - 1; + return static_cast( ix_ ) / 2 - 1; } template BOOST_CXX14_CONSTEXPR mp11::mp_at_c, I>& _get_impl( mp11::mp_size_t ) noexcept { + assert( index() == I ); + size_t const J = I+1; - assert( ix_ == J || -ix_ == J ); - constexpr mp11::mp_size_t j{}; - return ix_ >= 0? st1_.get( j ): st2_.get( j ); + return storage( ix_ & 1 ).get( j ); } template constexpr mp11::mp_at_c, I> const& _get_impl( mp11::mp_size_t ) const noexcept { + // assert( index() == I ); // size_t const J = I+1; - // assert( ix_ == J || -ix_ == J ); // constexpr mp_size_t j{}; - return ix_ >= 0? st1_.get( mp11::mp_size_t() ): st2_.get( mp11::mp_size_t() ); + return storage( ix_ & 1 ).get( mp11::mp_size_t() ); } template void emplace( A&&... a ) { size_t const J = I+1; - if( ix_ >= 0 ) - { - st2_.emplace( mp11::mp_size_t(), std::forward(a)... ); - _destroy(); + unsigned i2 = 1 - ( ix_ & 1 ); - ix_ = -static_cast( J ); - } - else - { - st1_.emplace( mp11::mp_size_t(), std::forward(a)... ); - _destroy(); + storage( i2 ).emplace( mp11::mp_size_t(), std::forward(a)... ); + _destroy(); - ix_ = J; - } + ix_ = J * 2 + i2; } }; @@ -2085,7 +2092,7 @@ template struct visit_L2 template auto operator()( I ) const -> Vret { auto f2 = bind_front( std::forward(f), unsafe_get( std::forward(v1) ) ); - return visit( f2, std::forward(v2) ); + return visit( f2, std::forward(v2) ); } };