Merge branch 'develop'

This commit is contained in:
Peter Dimov
2017-06-02 06:27:21 +03:00
4 changed files with 510 additions and 17 deletions

View File

@@ -0,0 +1,367 @@
#ifndef BOOST_VARIANT2_EXPECTED_HPP_INCLUDED
#define BOOST_VARIANT2_EXPECTED_HPP_INCLUDED
// Copyright 2017 Peter Dimov.
//
// Distributed under the Boost Software License, Version 1.0.
//
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
#ifndef BOOST_VARIANT2_VARIANT_HPP_INCLUDED
#include <boost/variant2/variant.hpp>
#endif
#include <boost/core/demangle.hpp>
#include <system_error>
#include <type_traits>
#include <typeinfo>
#include <cassert>
//
namespace boost
{
namespace variant2
{
// unexpected_
template<class... E> using unexpected_ = variant<E...>;
// bad_expected_access
class bad_expected_access: public std::exception
{
private:
std::string msg_;
public:
bad_expected_access() noexcept
{
}
template<class E> explicit bad_expected_access( mp_identity<E> ) noexcept: msg_( "bad_expected_access: " + boost::core::demangle( typeid(E).name() ) )
{
}
char const * what() const noexcept
{
return msg_.empty()? "bad_expected_access": msg_.c_str();
}
};
// expected
template<class E> void throw_on_unexpected( E const & /*e*/ )
{
throw bad_expected_access( mp_identity<E>() );
}
void throw_on_unexpected( std::error_code const & e )
{
throw std::system_error( e );
}
void throw_on_unexpected( std::exception_ptr const & e )
{
if( e )
{
std::rethrow_exception( e );
}
else
{
throw bad_expected_access( mp_identity<std::exception_ptr>() );
}
}
template<class T, class... E> class expected
{
private:
variant<T, E...> v_;
private:
void _bad_access() const
{
mp_for_index<mp_size<expected>>( v_.index(), [&]( auto I )
{
if( I == 0 )
{
throw bad_expected_access( mp_identity<T>() );
}
else
{
throw_on_unexpected( get<I>(v_) );
}
});
}
public:
// value constructors
constexpr expected() noexcept( std::is_nothrow_default_constructible<T>::value )
{
}
constexpr expected( T const& t ) noexcept( std::is_nothrow_copy_constructible<T>::value ): v_( in_place_index<0>, t )
{
}
constexpr expected( T && t ) noexcept( std::is_nothrow_move_constructible<T>::value ): v_( in_place_index<0>, std::move(t) )
{
}
// template<class U> constexpr expected( U && u ); where U in E...?
// in-place constructor?
// unexpected constructor
template<class... E2,
class En = mp_if<mp_all<std::is_copy_constructible<E2>..., mp_contains<mp_list<E...>, E2>...>, void>>
constexpr expected( unexpected_<E2...> const & x ): v_( x )
{
}
template<class... E2,
class En = mp_if<mp_all<std::is_copy_constructible<E2>..., mp_contains<mp_list<E...>, E2>...>, void>>
constexpr expected( unexpected_<E2...> && x ): v_( std::move(x) )
{
}
// conversion constructor
template<class... E2,
class En = mp_if<mp_all<std::is_copy_constructible<E2>..., mp_contains<mp_list<E...>, E2>...>, void>>
constexpr expected( expected<T, E2...> const & x ): v_( x.v_ )
{
}
template<class... E2,
class En = mp_if<mp_all<std::is_move_constructible<E2>..., mp_contains<mp_list<E...>, E2>...>, void>>
constexpr expected( expected<T, E2...> && x ): v_( std::move(x.v_) )
{
}
// emplace
template<class... A> void emplace( A&&... a )
{
v_.emplace( std::forward<A>(a)... );
}
template<class V, class... A> void emplace( std::initializer_list<V> il, A&&... a )
{
v_.emplace( il, std::forward<A>(a)... );
}
// swap
void swap( expected & r ) noexcept( noexcept( v_.swap( r.v_ ) ) )
{
v_.swap( r.v_ );
}
// value queries
constexpr bool has_value() const noexcept
{
return v_.index() == 0;
}
constexpr explicit operator bool() const noexcept
{
return v_.index() == 0;
}
// checked value access
constexpr T& value() &
{
if( !has_value() )
{
_bad_access();
}
return *get_if<0>(&v_);
}
constexpr T const& value() const&
{
if( !has_value() )
{
_bad_access();
}
return *get_if<0>(&v_);
}
constexpr T&& value() &&
{
return std::move( value() );
}
constexpr T const&& value() const&&
{
return std::move( value() );
}
// unchecked value access
T* operator->() noexcept
{
return get_if<0>(&v_);
}
T const* operator->() const noexcept
{
return get_if<0>(&v_);
}
T& operator*() & noexcept
{
T* p = get_if<0>(&v_);
assert( p != 0 );
return *p;
}
T const& operator*() const & noexcept
{
T const* p = get_if<0>(&v_);
assert( p != 0 );
return *p;
}
T&& operator*() && noexcept
{
return std::move(**this);
}
T const&& operator*() const && noexcept
{
return std::move(**this);
}
// error queries
template<class E2> constexpr bool has_error() const noexcept
{
using I = mp_find<expected, E2>;
return v_.index() == I::value;
}
constexpr bool has_error() const noexcept
{
static_assert( sizeof...(E) == 1, "has_error() is only valid when there is a single E" );
return has_error<mp_first<expected>>();
}
// error access
unexpected_<E...> unexpected() const
{
if( has_value() )
{
_bad_access();
}
return v_.template subset<E...>();
}
template<class E2> constexpr E2 error() const noexcept
{
using I = mp_find<expected, E2>;
if( v_.index() != I::value )
{
_bad_access();
}
return get<I>( v_ );
}
constexpr mp_first<expected> error() const noexcept
{
static_assert( sizeof...(E) == 1, "error() is only valid when there is a single E" );
return error<mp_first<expected>>();
}
// error mapping
private:
template<class F> struct Qret
{
template<class... A> using fn = decltype( std::declval<F>()( std::declval<A>()... ) );
};
template<class F> using remapped = mp_append<expected<T>, mp_unique<mp_transform_q<Qret<F>, mp_list<E...>>>>;
template<class R, std::size_t I, class F, class V> static R _remap_error( mp_size_t<I>, F && f, V && v )
{
// return R( std::forward<F>(f)( std::forward<V>(v) ) );
auto e = std::forward<F>(f)( std::forward<V>(v) );
return unexpected_<decltype(e)>{ e };
}
template<class R, class F, class V> static R _remap_error( mp_size_t<0>, F && /*f*/, V && v )
{
return R( std::forward<V>(v) );
}
public:
template<class F> remapped<F> remap_errors( F && f ) const
{
using R = remapped<F>;
return mp_for_index<mp_size<expected>>( v_.index(), [&]( auto I ) {
return _remap_error<R>( I, f, get<I>(v_) );
});
}
expected<T, std::error_code> remap_errors()
{
using R = expected<T, std::error_code>;
auto f = []( auto const& e ){ return make_error_code(e); };
return mp_for_index<mp_size<expected>>( v_.index(), [&]( auto I ) {
return _remap_error<R>( I, f, get<I>(v_) );
});
}
};
template<class T, class... E> inline constexpr bool operator==( expected<T, E...> const & x1, expected<T, E...> const & x2 )
{
return x1.v_ == x2.v_;
}
template<class T, class... E> inline constexpr bool operator!=( expected<T, E...> const & x1, expected<T, E...> const & x2 )
{
return x1.v_ != x2.v_;
}
template<class T, class... E> inline void swap( expected<T, E...> & x1, expected<T, E...> & x2 ) noexcept( noexcept( x1.swap( x2 ) ) )
{
x1.swap( x2 );
}
} // namespace variant2
} // namespace boost
#endif // #ifndef BOOST_VARIANT2_EXPECTED_HPP_INCLUDED

View File

@@ -376,9 +376,10 @@ template<class T1, class... T> struct overload<T1, T...>: overload<T...>
#if BOOST_WORKAROUND( BOOST_MSVC, <= 1910 )
template<class U, class... T> struct resolve_overload_type_impl
template<class U, class... T> using resolve_overload_type_ = decltype( overload<T...>()(std::declval<U>()) );
template<class U, class... T> struct resolve_overload_type_impl: mp_defer< resolve_overload_type_, U, T... >
{
using type = decltype( overload<T...>()(std::declval<U>()) );
};
template<class U, class... T> using resolve_overload_type = typename resolve_overload_type_impl<U, T...>::type::type;
@@ -412,6 +413,11 @@ template<class... T> struct variant_base_impl<true, true, T...>
{
}
constexpr std::size_t index() const noexcept
{
return ix_ - 1;
}
template<std::size_t I> constexpr mp_at_c<variant<T...>, I>& _get_impl( mp_size_t<I> ) noexcept
{
size_t const J = I+1;
@@ -485,6 +491,11 @@ template<class... T> struct variant_base_impl<true, false, T...>
{
}
constexpr std::size_t index() const noexcept
{
return ix_ >= 0? ix_ - 1: -ix_ - 1;
}
template<std::size_t I> constexpr mp_at_c<variant<T...>, I>& _get_impl( mp_size_t<I> ) noexcept
{
size_t const J = I+1;
@@ -554,6 +565,11 @@ template<class... T> struct variant_base_impl<false, true, T...>
_destroy();
}
constexpr std::size_t index() const noexcept
{
return ix_ - 1;
}
template<std::size_t I> constexpr mp_at_c<variant<T...>, I>& _get_impl( mp_size_t<I> ) noexcept
{
size_t const J = I+1;
@@ -660,6 +676,11 @@ template<class... T> struct variant_base_impl<false, false, T...>
_destroy();
}
constexpr std::size_t index() const noexcept
{
return ix_ >= 0? ix_ - 1: -ix_ - 1;
}
template<std::size_t I> constexpr mp_at_c<variant<T...>, I>& _get_impl( mp_size_t<I> ) noexcept
{
size_t const J = I+1;
@@ -871,11 +892,11 @@ public:
if( this->index() == I )
{
get<I>(*this) = get<I>(r);
this->_get_impl( I ) = r._get_impl( I );
}
else
{
this->variant_base::template emplace<I>( get<I>(r) );
this->variant_base::template emplace<I>( r._get_impl( I ) );
}
});
@@ -891,11 +912,11 @@ public:
if( this->index() == I )
{
get<I>(*this) = get<I>(std::move(r));
this->_get_impl( I ) = std::move( r._get_impl( I ) );
}
else
{
this->variant_base::template emplace<I>( get<I>(std::move(r)) );
this->variant_base::template emplace<I>( std::move( r._get_impl( I ) ) );
}
});
@@ -957,10 +978,7 @@ public:
// value status
constexpr size_t index() const noexcept
{
return this->ix_ >= 0? this->ix_ - 1 : -this->ix_ - 1;
}
using variant_base::index;
// swap
@@ -971,7 +989,7 @@ public:
mp_for_index<sizeof...(T)>( index(), [&]( auto I ){
using std::swap;
swap( get<I>(*this), get<I>(r) );
swap( this->_get_impl( I ), r._get_impl( I ) );
});
}
@@ -991,6 +1009,104 @@ public:
}
using variant_base::_get_impl;
// converting constructors (extension)
template<class... U,
class E2 = mp_if<mp_all<std::is_copy_constructible<U>..., mp_contains<mp_list<T...>, U>...>, void> >
variant( variant<U...> const& r )
noexcept( mp_all<std::is_nothrow_copy_constructible<U>...>::value )
{
mp_for_index<sizeof...(U)>( r.index(), [&]( auto I ){
using J = mp_find<mp_list<T...>, mp_at_c<mp_list<U...>, I>>;
::new( static_cast<variant_base*>(this) ) variant_base( J{}, r._get_impl( I ) );
});
}
template<class... U,
class E2 = mp_if<mp_all<std::is_move_constructible<U>..., mp_contains<mp_list<T...>, U>...>, void> >
variant( variant<U...> && r )
noexcept( mp_all<std::is_nothrow_move_constructible<U>...>::value )
{
mp_for_index<sizeof...(U)>( r.index(), [&]( auto I ){
using J = mp_find<mp_list<T...>, mp_at_c<mp_list<U...>, I>>;
::new( static_cast<variant_base*>(this) ) variant_base( J{}, std::move( r._get_impl( I ) ) );
});
}
// subset (extension)
private:
template<class... U, class V, std::size_t J, class E = std::enable_if_t<J != sizeof...(U)>> static variant<U...> _subset_impl( mp_size_t<J>, V && v )
{
return variant<U...>( in_place_index<J>, std::forward<V>(v) );
}
template<class... U, class V> static variant<U...> _subset_impl( mp_size_t<sizeof...(U)>, V && /*v*/ )
{
throw bad_variant_access();
}
public:
template<class... U,
class E2 = mp_if<mp_all<std::is_copy_constructible<U>..., mp_contains<mp_list<T...>, U>...>, void> >
constexpr variant<U...> subset() &
{
return mp_for_index<sizeof...(T)>( index(), [&]( auto I ){
using J = mp_find<mp_list<U...>, mp_at_c<mp_list<T...>, I>>;
return _subset_impl<U...>( J{}, this->_get_impl( I ) );
});
}
template<class... U,
class E2 = mp_if<mp_all<std::is_copy_constructible<U>..., mp_contains<mp_list<T...>, U>...>, void> >
constexpr variant<U...> subset() const&
{
return mp_for_index<sizeof...(T)>( index(), [&]( auto I ){
using J = mp_find<mp_list<U...>, mp_at_c<mp_list<T...>, I>>;
return _subset_impl<U...>( J{}, this->_get_impl( I ) );
});
}
template<class... U,
class E2 = mp_if<mp_all<std::is_copy_constructible<U>..., mp_contains<mp_list<T...>, U>...>, void> >
constexpr variant<U...> subset() &&
{
return mp_for_index<sizeof...(T)>( index(), [&]( auto I ){
using J = mp_find<mp_list<U...>, mp_at_c<mp_list<T...>, I>>;
return _subset_impl<U...>( J{}, std::move( this->_get_impl( I ) ) );
});
}
template<class... U,
class E2 = mp_if<mp_all<std::is_copy_constructible<U>..., mp_contains<mp_list<T...>, U>...>, void> >
constexpr variant<U...> subset() const&&
{
return mp_for_index<sizeof...(T)>( index(), [&]( auto I ){
using J = mp_find<mp_list<U...>, mp_at_c<mp_list<T...>, I>>;
return _subset_impl<U...>( J{}, std::move( this->_get_impl( I ) ) );
});
}
};
// relational operators
@@ -1000,7 +1116,7 @@ template<class... T> constexpr bool operator==( variant<T...> const & v, variant
return mp_for_index<sizeof...(T)>( v.index(), [&]( auto I ){
return get<I>(v) == get<I>(w);
return v._get_impl( I ) == w._get_impl( I );
});
}
@@ -1011,7 +1127,7 @@ template<class... T> constexpr bool operator!=( variant<T...> const & v, variant
return mp_for_index<sizeof...(T)>( v.index(), [&]( auto I ){
return get<I>(v) != get<I>(w);
return v._get_impl( I ) != w._get_impl( I );
});
}
@@ -1023,7 +1139,7 @@ template<class... T> constexpr bool operator<( variant<T...> const & v, variant<
return mp_for_index<sizeof...(T)>( v.index(), [&]( auto I ){
return get<I>(v) < get<I>(w);
return v._get_impl( I ) < w._get_impl( I );
});
}
@@ -1035,7 +1151,7 @@ template<class... T> constexpr bool operator>( variant<T...> const & v, variant
return mp_for_index<sizeof...(T)>( v.index(), [&]( auto I ){
return get<I>(v) > get<I>(w);
return v._get_impl( I ) > w._get_impl( I );
});
}
@@ -1047,7 +1163,7 @@ template<class... T> constexpr bool operator<=( variant<T...> const & v, variant
return mp_for_index<sizeof...(T)>( v.index(), [&]( auto I ){
return get<I>(v) <= get<I>(w);
return v._get_impl( I ) <= w._get_impl( I );
});
}
@@ -1059,7 +1175,7 @@ template<class... T> constexpr bool operator>=( variant<T...> const & v, variant
return mp_for_index<sizeof...(T)>( v.index(), [&]( auto I ){
return get<I>(v) >= get<I>(w);
return v._get_impl( I ) >= w._get_impl( I );
});
}

View File

@@ -121,7 +121,12 @@ int main()
BOOST_TEST_TRAIT_FALSE((std::is_nothrow_copy_constructible<variant<X1, X2, int, int>>));
BOOST_TEST_TRAIT_TRUE((std::is_copy_constructible<variant<X1, X2>>));
#if !BOOST_WORKAROUND( BOOST_MSVC, <= 1910 )
BOOST_TEST_TRAIT_FALSE((std::is_copy_constructible<variant<int, float, Y>>));
#endif
}
return boost::report_errors();

View File

@@ -122,7 +122,12 @@ int main()
BOOST_TEST_TRAIT_FALSE((std::is_nothrow_move_constructible<variant<X1, X2, int, int>>));
BOOST_TEST_TRAIT_TRUE((std::is_move_constructible<variant<X1, X2>>));
#if !BOOST_WORKAROUND( BOOST_MSVC, <= 1910 )
BOOST_TEST_TRAIT_FALSE((std::is_move_constructible<variant<int, float, Y>>));
#endif
}
return boost::report_errors();