forked from boostorg/variant2
Strong guarantee on emplace
This commit is contained in:
@ -598,11 +598,8 @@ template<class U, class... T> using resolve_overload_index = mp11::mp_find<mp11:
|
|||||||
|
|
||||||
// variant_base
|
// variant_base
|
||||||
|
|
||||||
template<class... T> using can_be_valueless = mp11::mp_any<std::is_same<T, monostate>..., std::is_nothrow_default_constructible<T>...>;
|
template<bool is_trivially_destructible, bool is_single_buffered, class... T> struct variant_base_impl;
|
||||||
template<class... T> using valueless_index = mp11::mp_if<mp11::mp_contains<mp11::mp_list<T...>, monostate>, mp11::mp_find<mp11::mp_list<T...>, monostate>, mp11::mp_find_if<mp11::mp_list<T...>, std::is_nothrow_default_constructible>>;
|
template<class... T> using variant_base = variant_base_impl<mp11::mp_all<std::is_trivially_destructible<T>...>::value, mp11::mp_all<std::is_nothrow_move_constructible<T>...>::value, T...>;
|
||||||
|
|
||||||
template<bool is_trivially_destructible, bool is_single_buffered, class... T> struct variant_base_impl; // trivially destructible, single buffered
|
|
||||||
template<class... T> using variant_base = variant_base_impl<mp11::mp_all<std::is_trivially_destructible<T>...>::value, mp11::mp_any<mp11::mp_all<std::is_nothrow_move_constructible<T>...>, can_be_valueless<T...>>::value, T...>;
|
|
||||||
|
|
||||||
struct none {};
|
struct none {};
|
||||||
|
|
||||||
@ -649,7 +646,7 @@ template<class... T> struct variant_base_impl<true, true, T...>
|
|||||||
return st1_.get( mp11::mp_size_t<I+1>() );
|
return st1_.get( mp11::mp_size_t<I+1>() );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t J, class U, bool B, class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_true, mp11::mp_bool<B>, A&&... a )
|
template<std::size_t J, class U, class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_true, A&&... a )
|
||||||
{
|
{
|
||||||
static_assert( std::is_nothrow_constructible<U, A&&...>::value, "Logic error: U must be nothrow constructible from A&&..." );
|
static_assert( std::is_nothrow_constructible<U, A&&...>::value, "Logic error: U must be nothrow constructible from A&&..." );
|
||||||
|
|
||||||
@ -657,7 +654,7 @@ template<class... T> struct variant_base_impl<true, true, T...>
|
|||||||
ix_ = J;
|
ix_ = J;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t J, class U, class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, mp11::mp_true, A&&... a )
|
template<std::size_t J, class U, class... A> BOOST_CXX14_CONSTEXPR void emplace_impl( mp11::mp_false, A&&... a )
|
||||||
{
|
{
|
||||||
static_assert( std::is_nothrow_move_constructible<U>::value, "Logic error: U must be nothrow move constructible" );
|
static_assert( std::is_nothrow_move_constructible<U>::value, "Logic error: U must be nothrow move constructible" );
|
||||||
|
|
||||||
@ -667,37 +664,12 @@ template<class... T> struct variant_base_impl<true, true, T...>
|
|||||||
ix_ = J;
|
ix_ = J;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t J, class U, class... A> void emplace_impl( mp11::mp_false, mp11::mp_false, A&&... a )
|
|
||||||
{
|
|
||||||
static_assert( can_be_valueless<T...>::value, "Logic error: T... must have a fallback type" );
|
|
||||||
|
|
||||||
std::size_t const K = valueless_index<T...>::value;
|
|
||||||
|
|
||||||
static_assert( K < sizeof...(T), "Logic error: T... must have a fallback index" );
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
st1_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
|
|
||||||
ix_ = J;
|
|
||||||
}
|
|
||||||
catch( ... )
|
|
||||||
{
|
|
||||||
st1_.emplace( mp11::mp_size_t<K+1>() );
|
|
||||||
ix_ = K+1;
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace( A&&... a )
|
template<std::size_t I, class... A> BOOST_CXX14_CONSTEXPR void emplace( A&&... a )
|
||||||
{
|
{
|
||||||
std::size_t const J = I+1;
|
std::size_t const J = I+1;
|
||||||
using U = mp11::mp_at_c<variant<T...>, I>;
|
using U = mp11::mp_at_c<variant<T...>, I>;
|
||||||
|
|
||||||
constexpr bool B1 = can_be_valueless<T...>::value;
|
this->emplace_impl<J, U>( std::is_nothrow_constructible<U, A&&...>(), std::forward<A>(a)... );
|
||||||
constexpr bool B2 = mp11::mp_all<detail::is_trivially_move_constructible<U>, detail::is_trivially_move_assignable<T>...>::value;
|
|
||||||
|
|
||||||
this->emplace_impl<J, U>( std::is_nothrow_constructible<U, A&&...>(), mp11::mp_bool<B2 || !B1>(), std::forward<A>(a)... );
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -836,42 +808,12 @@ template<class... T> struct variant_base_impl<false, true, T...>
|
|||||||
return st1_.get( mp11::mp_size_t<I+1>() );
|
return st1_.get( mp11::mp_size_t<I+1>() );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t J, class U, class... A> void emplace_impl( mp11::mp_int<0>, A&&... a )
|
template<std::size_t I, class... A> void emplace( A&&... a )
|
||||||
{
|
{
|
||||||
static_assert( std::is_nothrow_constructible<U, A&&...>::value, "Logic error: U must be nothrow constructible from A&&..." );
|
size_t const J = I+1;
|
||||||
|
|
||||||
_destroy();
|
using U = mp11::mp_at_c<variant<T...>, I>;
|
||||||
|
|
||||||
st1_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
|
|
||||||
ix_ = J;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t J, class U, class... A> void emplace_impl( mp11::mp_int<1>, A&&... a )
|
|
||||||
{
|
|
||||||
static_assert( can_be_valueless<T...>::value, "Logic error: T... must have a fallback type" );
|
|
||||||
|
|
||||||
std::size_t const K = valueless_index<T...>::value;
|
|
||||||
|
|
||||||
static_assert( K < sizeof...(T), "Logic error: T... must have a fallback index" );
|
|
||||||
|
|
||||||
_destroy();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
st1_.emplace( mp11::mp_size_t<J>(), std::forward<A>(a)... );
|
|
||||||
ix_ = J;
|
|
||||||
}
|
|
||||||
catch( ... )
|
|
||||||
{
|
|
||||||
st1_.emplace( mp11::mp_size_t<K+1>() );
|
|
||||||
ix_ = K+1;
|
|
||||||
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t J, class U, class... A> void emplace_impl( mp11::mp_int<2>, A&&... a )
|
|
||||||
{
|
|
||||||
static_assert( std::is_nothrow_move_constructible<U>::value, "Logic error: U must be nothrow move constructible" );
|
static_assert( std::is_nothrow_move_constructible<U>::value, "Logic error: U must be nothrow move constructible" );
|
||||||
|
|
||||||
U tmp( std::forward<A>(a)... );
|
U tmp( std::forward<A>(a)... );
|
||||||
@ -881,17 +823,6 @@ template<class... T> struct variant_base_impl<false, true, T...>
|
|||||||
st1_.emplace( mp11::mp_size_t<J>(), std::move(tmp) );
|
st1_.emplace( mp11::mp_size_t<J>(), std::move(tmp) );
|
||||||
ix_ = J;
|
ix_ = J;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I, class... A> void emplace( A&&... a )
|
|
||||||
{
|
|
||||||
size_t const J = I+1;
|
|
||||||
|
|
||||||
using U = mp11::mp_at_c<variant<T...>, I>;
|
|
||||||
|
|
||||||
int const D = std::is_nothrow_constructible<U, A&&...>::value? 0: ( can_be_valueless<T...>::value? 1: 2 );
|
|
||||||
|
|
||||||
this->emplace_impl<J, U>( mp11::mp_int<D>(), std::forward<A>(a)... );
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// not trivially destructible, double buffered
|
// not trivially destructible, double buffered
|
||||||
|
@ -115,8 +115,8 @@ int main()
|
|||||||
}
|
}
|
||||||
catch( std::exception const& )
|
catch( std::exception const& )
|
||||||
{
|
{
|
||||||
// basic guarantee; X1 is nothrow default-constructible
|
// strong guarantee
|
||||||
BOOST_TEST_EQ( v.index(), 1 );
|
BOOST_TEST_EQ( v.index(), 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,8 +132,8 @@ int main()
|
|||||||
}
|
}
|
||||||
catch( std::exception const& )
|
catch( std::exception const& )
|
||||||
{
|
{
|
||||||
// basic guarantee; X1 is nothrow default-constructible
|
// strong guarantee
|
||||||
BOOST_TEST_EQ( v.index(), 0 );
|
BOOST_TEST_EQ( v.index(), 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,8 +149,8 @@ int main()
|
|||||||
}
|
}
|
||||||
catch( std::exception const& )
|
catch( std::exception const& )
|
||||||
{
|
{
|
||||||
// basic guarantee; monostate
|
// strong guarantee
|
||||||
BOOST_TEST_EQ( v.index(), 2 );
|
BOOST_TEST_EQ( v.index(), 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,8 +166,8 @@ int main()
|
|||||||
}
|
}
|
||||||
catch( std::exception const& )
|
catch( std::exception const& )
|
||||||
{
|
{
|
||||||
// basic guarantee; monostate
|
// strong guarantee
|
||||||
BOOST_TEST_EQ( v.index(), 2 );
|
BOOST_TEST_EQ( v.index(), 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,8 +183,8 @@ int main()
|
|||||||
}
|
}
|
||||||
catch( std::exception const& )
|
catch( std::exception const& )
|
||||||
{
|
{
|
||||||
// basic guarantee; X1 is nothrow default-constructible
|
// strong guarantee
|
||||||
BOOST_TEST_EQ( v.index(), 2 );
|
BOOST_TEST_EQ( v.index(), 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,8 +200,8 @@ int main()
|
|||||||
}
|
}
|
||||||
catch( std::exception const& )
|
catch( std::exception const& )
|
||||||
{
|
{
|
||||||
// basic guarantee; monostate
|
// strong guarantee
|
||||||
BOOST_TEST_EQ( v.index(), 3 );
|
BOOST_TEST_EQ( v.index(), 0 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,18 +234,8 @@ int main()
|
|||||||
}
|
}
|
||||||
catch( std::exception const& )
|
catch( std::exception const& )
|
||||||
{
|
{
|
||||||
// X3 is not v2d::trivially_move_assignable on libstdc++ 4.x
|
// strong guarantee
|
||||||
|
BOOST_TEST_EQ( v.index(), 0 );
|
||||||
if( v2d::is_trivially_move_assignable<X3>::value )
|
|
||||||
{
|
|
||||||
// all trivially destructible and move-assignable, no change
|
|
||||||
BOOST_TEST_EQ( v.index(), 0 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// basic guarantee; X1 is nothrow default-constructible
|
|
||||||
BOOST_TEST_EQ( v.index(), 1 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,18 +251,8 @@ int main()
|
|||||||
}
|
}
|
||||||
catch( std::exception const& )
|
catch( std::exception const& )
|
||||||
{
|
{
|
||||||
// X3 is not v2d::trivially_move_assignable on libstdc++ 4.x
|
// strong guarantee
|
||||||
|
BOOST_TEST_EQ( v.index(), 0 );
|
||||||
if( v2d::is_trivially_move_assignable<X3>::value )
|
|
||||||
{
|
|
||||||
// all trivially destructible and move-assignable, no change
|
|
||||||
BOOST_TEST_EQ( v.index(), 0 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// basic guarantee; monostate
|
|
||||||
BOOST_TEST_EQ( v.index(), 2 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user