#ifndef BOOST_SYSTEM_RESULT_HPP_INCLUDED #define BOOST_SYSTEM_RESULT_HPP_INCLUDED // Copyright 2017, 2021, 2022 Peter Dimov. // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include #include #include #include #include #include #include #include #include #include #include #include #include #include // namespace boost { namespace system { // throw_exception_from_error #if defined(__GNUC__) && __GNUC__ >= 7 && __GNUC__ <= 8 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wattributes" #endif BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( error_code const & e, boost::source_location const& loc ) { boost::throw_with_location( system_error( e ), loc ); } BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( errc::errc_t const & e, boost::source_location const& loc ) { boost::throw_with_location( system_error( make_error_code( e ) ), loc ); } BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( std::error_code const & e, boost::source_location const& loc ) { boost::throw_with_location( std::system_error( e ), loc ); } BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( std::errc const & e, boost::source_location const& loc ) { boost::throw_with_location( std::system_error( make_error_code( e ) ), loc ); } BOOST_NORETURN BOOST_NOINLINE inline void throw_exception_from_error( std::exception_ptr const & p, boost::source_location const& loc ) { if( p ) { std::rethrow_exception( p ); } else { boost::throw_with_location( std::bad_exception(), loc ); } } #if defined(__GNUC__) && __GNUC__ >= 7 && __GNUC__ <= 8 # pragma GCC diagnostic pop #endif // in_place_* using in_place_value_t = variant2::in_place_index_t<0>; constexpr in_place_value_t in_place_value{}; using in_place_error_t = variant2::in_place_index_t<1>; constexpr in_place_error_t in_place_error{}; namespace detail { template using remove_cvref = typename std::remove_cv< typename std::remove_reference::type >::type; template using is_errc_t = std::is_same...>, mp11::mp_list>; } // namespace detail // result template class result { private: variant2::variant v_; public: // constructors // default template::value && std::is_default_constructible::value >::type> constexpr result() noexcept( std::is_nothrow_default_constructible::value ) : v_( in_place_value ) { } // implicit, value template::value && !(detail::is_errc_t::value && std::is_arithmetic::value) && !std::is_constructible::value, int>::type = 0> constexpr result( A&& a ) noexcept( std::is_nothrow_constructible::value ) : v_( in_place_value, std::forward(a) ) { } // implicit, error template::value && !std::is_constructible::value, int>::type = 0> constexpr result( A&& a ) noexcept( std::is_nothrow_constructible::value ) : v_( in_place_error, std::forward(a) ) { } // explicit, value template::value && !(detail::is_errc_t::value && std::is_arithmetic::value) && !std::is_constructible::value >::type> explicit constexpr result( A&&... a ) noexcept( std::is_nothrow_constructible::value ) : v_( in_place_value, std::forward(a)... ) { } // explicit, error template::value && std::is_constructible::value >::type> explicit constexpr result( A&&... a ) noexcept( std::is_nothrow_constructible::value ) : v_( in_place_error, std::forward(a)... ) { } // tagged, value template::value >::type> constexpr result( in_place_value_t, A&&... a ) noexcept( std::is_nothrow_constructible::value ) : v_( in_place_value, std::forward(a)... ) { } // tagged, error template::value >::type> constexpr result( in_place_error_t, A&&... a ) noexcept( std::is_nothrow_constructible::value ) : v_( in_place_error, std::forward(a)... ) { } // queries constexpr bool has_value() const noexcept { return v_.index() == 0; } constexpr bool has_error() const noexcept { return v_.index() != 0; } constexpr explicit operator bool() const noexcept { return v_.index() == 0; } // checked value access #if defined( BOOST_NO_CXX11_REF_QUALIFIERS ) BOOST_CXX14_CONSTEXPR T value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const { if( has_value() ) { return variant2::unsafe_get<0>( v_ ); } else { throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc ); } } #else BOOST_CXX14_CONSTEXPR T& value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) & { if( has_value() ) { return variant2::unsafe_get<0>( v_ ); } else { throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc ); } } BOOST_CXX14_CONSTEXPR T const& value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const& { if( has_value() ) { return variant2::unsafe_get<0>( v_ ); } else { throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc ); } } template BOOST_CXX14_CONSTEXPR typename std::enable_if::value, T>::type value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) && { return std::move( value( loc ) ); } template BOOST_CXX14_CONSTEXPR typename std::enable_if::value, T&&>::type value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) && { return std::move( value( loc ) ); } template BOOST_CXX14_CONSTEXPR typename std::enable_if::value, T>::type value() const && = delete; template BOOST_CXX14_CONSTEXPR typename std::enable_if::value, T const&&>::type value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const && { return std::move( value( loc ) ); } #endif // unchecked value access BOOST_CXX14_CONSTEXPR T* operator->() noexcept { return variant2::get_if<0>( &v_ ); } BOOST_CXX14_CONSTEXPR T const* operator->() const noexcept { return variant2::get_if<0>( &v_ ); } #if defined( BOOST_NO_CXX11_REF_QUALIFIERS ) BOOST_CXX14_CONSTEXPR T& operator*() noexcept { T* p = operator->(); BOOST_ASSERT( p != 0 ); return *p; } BOOST_CXX14_CONSTEXPR T const& operator*() const noexcept { T const* p = operator->(); BOOST_ASSERT( p != 0 ); return *p; } #else BOOST_CXX14_CONSTEXPR T& operator*() & noexcept { T* p = operator->(); BOOST_ASSERT( p != 0 ); return *p; } BOOST_CXX14_CONSTEXPR T const& operator*() const & noexcept { T const* p = operator->(); BOOST_ASSERT( p != 0 ); return *p; } template BOOST_CXX14_CONSTEXPR typename std::enable_if::value, T>::type operator*() && noexcept(std::is_nothrow_move_constructible::value) { return std::move(**this); } template BOOST_CXX14_CONSTEXPR typename std::enable_if::value, T&&>::type operator*() && noexcept { return std::move(**this); } template BOOST_CXX14_CONSTEXPR typename std::enable_if::value, T>::type operator*() const && noexcept = delete; template BOOST_CXX14_CONSTEXPR typename std::enable_if::value, T const&&>::type operator*() const && noexcept { return std::move(**this); } #endif // error access constexpr E error() const noexcept( std::is_nothrow_default_constructible::value && std::is_nothrow_copy_constructible::value ) { return has_error()? variant2::unsafe_get<1>( v_ ): E(); } // swap BOOST_CXX14_CONSTEXPR void swap( result& r ) noexcept( noexcept( v_.swap( r.v_ ) ) ) { v_.swap( r.v_ ); } friend BOOST_CXX14_CONSTEXPR void swap( result & r1, result & r2 ) noexcept( noexcept( r1.swap( r2 ) ) ) { r1.swap( r2 ); } // equality friend constexpr bool operator==( result const & r1, result const & r2 ) noexcept( noexcept( r1.v_ == r2.v_ ) ) { return r1.v_ == r2.v_; } friend constexpr bool operator!=( result const & r1, result const & r2 ) noexcept( noexcept( !( r1 == r2 ) ) ) { return !( r1 == r2 ); } }; template std::basic_ostream& operator<<( std::basic_ostream& os, result const & r ) { if( r.has_value() ) { os << "value:" << *r; } else { os << "error:" << r.error(); } return os; } // result template class result { private: variant2::variant v_; public: // constructors // default constexpr result() noexcept : v_( in_place_value ) { } // explicit, error template::value && !std::is_convertible::value >::type> explicit constexpr result( A&& a ) noexcept( std::is_nothrow_constructible::value ) : v_( in_place_error, std::forward(a) ) { } // implicit, error template::value >::type> constexpr result( A&& a ) noexcept( std::is_nothrow_constructible::value ) : v_( in_place_error, std::forward(a) ) { } // more than one arg, error template::value && sizeof...(A) >= 2 >::type> constexpr result( A&&... a ) noexcept( std::is_nothrow_constructible::value ) : v_( in_place_error, std::forward(a)... ) { } // tagged, value constexpr result( in_place_value_t ) noexcept : v_( in_place_value ) { } // tagged, error template::value >::type> constexpr result( in_place_error_t, A&&... a ) noexcept( std::is_nothrow_constructible::value ) : v_( in_place_error, std::forward(a)... ) { } // queries constexpr bool has_value() const noexcept { return v_.index() == 0; } constexpr bool has_error() const noexcept { return v_.index() != 0; } constexpr explicit operator bool() const noexcept { return v_.index() == 0; } // checked value access BOOST_CXX14_CONSTEXPR void value( boost::source_location const& loc = BOOST_CURRENT_LOCATION ) const { if( has_value() ) { } else { throw_exception_from_error( variant2::unsafe_get<1>( v_ ), loc ); } } // unchecked value access BOOST_CXX14_CONSTEXPR void* operator->() noexcept { return variant2::get_if<0>( &v_ ); } BOOST_CXX14_CONSTEXPR void const* operator->() const noexcept { return variant2::get_if<0>( &v_ ); } BOOST_CXX14_CONSTEXPR void operator*() const noexcept { BOOST_ASSERT( has_value() ); } // error access constexpr E error() const noexcept( std::is_nothrow_default_constructible::value && std::is_nothrow_copy_constructible::value ) { return has_error()? variant2::unsafe_get<1>( v_ ): E(); } // swap BOOST_CXX14_CONSTEXPR void swap( result& r ) noexcept( noexcept( v_.swap( r.v_ ) ) ) { v_.swap( r.v_ ); } friend BOOST_CXX14_CONSTEXPR void swap( result & r1, result & r2 ) noexcept( noexcept( r1.swap( r2 ) ) ) { r1.swap( r2 ); } // equality friend constexpr bool operator==( result const & r1, result const & r2 ) noexcept( noexcept( r1.v_ == r2.v_ ) ) { return r1.v_ == r2.v_; } friend constexpr bool operator!=( result const & r1, result const & r2 ) noexcept( noexcept( !( r1 == r2 ) ) ) { return !( r1 == r2 ); } }; template std::basic_ostream& operator<<( std::basic_ostream& os, result const & r ) { if( r.has_value() ) { os << "value:void"; } else { os << "error:" << r.error(); } return os; } } // namespace system } // namespace boost #endif // #ifndef BOOST_SYSTEM_RESULT_HPP_INCLUDED