diff --git a/include/boost/system/result.hpp b/include/boost/system/result.hpp new file mode 100644 index 0000000..46782dd --- /dev/null +++ b/include/boost/system/result.hpp @@ -0,0 +1,341 @@ +#ifndef BOOST_RESULT_RESULT_HPP_INCLUDED +#define BOOST_RESULT_RESULT_HPP_INCLUDED + +// Copyright 2017, 2021 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 + +// + +namespace boost +{ +namespace result +{ + +// throw_exception_from_error_code + +BOOST_NORETURN void throw_exception_from_error_code( std::error_code const & e ) +{ + boost::throw_exception( std::system_error( e ) ); +} + +// 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{}; + +// 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 ) + { + } + + // explicit, value + template::value && + !std::is_convertible::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_convertible::value && + !std::is_constructible::value + >::type> + explicit constexpr result( A&& a ) + noexcept( std::is_nothrow_constructible::value ) + : v_( in_place_error, std::forward(a) ) + { + } + + // implicit, value + template::value && + !std::is_constructible::value + >::type> + 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 + >::type> + constexpr result( A&& a ) + noexcept( std::is_nothrow_constructible::value ) + : v_( in_place_error, std::forward(a) ) + { + } + + // more than one arg, value + template::value && + !std::is_constructible::value && + sizeof...(A) >= 2 + >::type> + constexpr result( A&&... a ) + noexcept( std::is_nothrow_constructible::value ) + : v_( in_place_value, std::forward(a)... ) + { + } + + // more than one arg, error + template::value && + std::is_constructible::value && + sizeof...(A) >= 2 + >::type> + 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() const + { + if( has_value() ) + { + return *variant2::get_if<0>( &v_ ); + } + else + { + throw_exception_from_error_code( *variant2::get_if<1>( &v_ ) ); + } + } + +#else + + BOOST_CXX14_CONSTEXPR T& value() & + { + if( has_value() ) + { + return *variant2::get_if<0>( &v_ ); + } + else + { + throw_exception_from_error_code( *variant2::get_if<1>( &v_ ) ); + } + } + + BOOST_CXX14_CONSTEXPR T const& value() const& + { + if( has_value() ) + { + return *variant2::get_if<0>( &v_ ); + } + else + { + throw_exception_from_error_code( *variant2::get_if<1>( &v_ ) ); + } + } + + BOOST_CXX14_CONSTEXPR T&& value() && + { + return std::move( value() ); + } + + BOOST_CXX14_CONSTEXPR T const&& value() const&& + { + return std::move( value() ); + } + +#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; + } + + BOOST_CXX14_CONSTEXPR T&& operator*() && noexcept + { + return std::move(**this); + } + + BOOST_CXX14_CONSTEXPR T const&& operator*() const && noexcept + { + return std::move(**this); + } + +#endif + + // error access + + BOOST_CXX14_CONSTEXPR E error() const + noexcept( std::is_nothrow_default_constructible::value && std::is_nothrow_copy_constructible::value ) + { + E const * p = variant2::get_if<1>( &v_ ); + return p? *p: 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; +} + +} // namespace result +} // namespace boost + +#endif // #ifndef BOOST_RESULT_RESULT_HPP_INCLUDED diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0b7103a..fc62a42 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1,7 +1,7 @@ # Boost System Library test Jamfile # Copyright Beman Dawes 2003, 2006 -# Copyright 2017-2019 Peter Dimov +# Copyright 2017-2021 Peter Dimov # Distributed under the Boost Software License, Version 1.0. # See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt @@ -10,6 +10,18 @@ import testing ; +project + : default-build + + extra + + : requirements + + msvc:on + gcc:on + clang:on + ; + rule system-run ( sources + ) { local result ; @@ -110,3 +122,21 @@ run std_interop_test8.cpp ; run std_interop_test9.cpp ; run ec_location_test.cpp ; + +# result + +import ../../config/checks/config : requires ; + +CPP11 = [ requires cxx11_variadic_templates cxx11_template_aliases cxx11_decltype cxx11_constexpr cxx11_noexcept ] ; + +run result_default_construct.cpp : : : $(CPP11) ; +run result_value_construct.cpp : : : $(CPP11) ; +run result_error_construct.cpp : : : $(CPP11) ; +run result_copy_construct.cpp : : : $(CPP11) ; +run result_move_construct.cpp : : : $(CPP11) ; +run result_copy_assign.cpp : : : $(CPP11) ; +run result_move_assign.cpp : : : $(CPP11) ; +run result_value_access.cpp : : : $(CPP11) ; +run result_error_access.cpp : : : $(CPP11) ; +run result_swap.cpp : : : $(CPP11) gcc-10:"-Wno-maybe-uninitialized" ; +run result_eq.cpp : : : $(CPP11) ; diff --git a/test/result_copy_assign.cpp b/test/result_copy_assign.cpp new file mode 100644 index 0000000..3f11082 --- /dev/null +++ b/test/result_copy_assign.cpp @@ -0,0 +1,605 @@ +// Copyright 2017, 2021 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 + +using namespace boost::result; + +struct X +{ + static int instances; + + int v_; + + explicit X( int v = 0 ): v_( v ) { ++instances; } + + X( X const& r ): v_( r.v_ ) { ++instances; } + + X& operator=( X const& ) = default; + + ~X() { --instances; } +}; + +bool operator==( X const & x1, X const & x2 ) +{ + return x1.v_ == x2.v_; +} + +std::ostream& operator<<( std::ostream& os, X const & x ) +{ + os << "X:" << x.v_; + return os; +} + +int X::instances = 0; + +struct Y +{ + static int instances; + + int v_; + + explicit Y( int v = 0 ): v_( v ) { ++instances; } + + Y( Y const& r ) noexcept: v_( r.v_ ) { ++instances; } + + Y& operator=( Y const& ) = default; + + ~Y() { --instances; } +}; + +bool operator==( Y const & y1, Y const & y2 ) +{ + return y1.v_ == y2.v_; +} + +std::ostream& operator<<( std::ostream& os, Y const & y ) +{ + os << "Y:" << y.v_; + return os; +} + +int Y::instances = 0; + +int main() +{ + // default-initialized lhs + + { + result r; + result r2; + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + result r; + result r2( 1 ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + result r; + result r2( ENOENT, std::generic_category() ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + result const r; + result r2; + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + result const r; + result r2( 1 ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + result const r; + result r2( ENOENT, std::generic_category() ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r; + result r2; + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r; + result r2( 1 ); + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r; + result r2( ENOENT, std::generic_category() ); + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result const r; + result r2; + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result const r; + result r2( 1 ); + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result const r; + result r2( ENOENT, std::generic_category() ); + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + // value lhs + + { + result r( 0 ); + result r2; + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + result r( 0 ); + result r2( 1 ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + result r( 0 ); + result r2( ENOENT, std::generic_category() ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + result const r( 0 ); + result r2; + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + result const r( 0 ); + result r2( 1 ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + result const r( 0 ); + result r2( ENOENT, std::generic_category() ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2; + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2( 2 ); + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2( ENOENT, std::generic_category() ); + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result const r( 1 ); + result r2; + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result const r( 1 ); + result r2( 2 ); + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result const r( 1 ); + result r2( ENOENT, std::generic_category() ); + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + // error lhs + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2; + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2( 1 ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2( ENOENT, std::generic_category() ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result const r( ec ); + result r2; + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result const r( ec ); + result r2( 1 ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result const r( ec ); + result r2( ENOENT, std::generic_category() ); + + r2 = r; + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2; + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 0 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2( 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 0 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2( ENOENT, std::generic_category() ); + + BOOST_TEST_EQ( X::instances, 0 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 0 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result const r( ec ); + result r2; + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 0 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result const r( ec ); + result r2( 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 0 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result const r( ec ); + result r2( ENOENT, std::generic_category() ); + + BOOST_TEST_EQ( X::instances, 0 ); + + r2 = r; + + BOOST_TEST_EQ( X::instances, 0 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + // + + BOOST_TEST_EQ( Y::instances, 0 ); + + { + result r( 1 ); + result r2( 2 ); + + BOOST_TEST_EQ( Y::instances, 2 ); + + r2 = r; + + BOOST_TEST_EQ( Y::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( Y::instances, 0 ); + + { + result r( 1 ); + result r2( "str" ); + + BOOST_TEST_EQ( Y::instances, 1 ); + + r2 = r; + + BOOST_TEST_EQ( Y::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( Y::instances, 0 ); + + { + result const r( 1 ); + result r2( 2 ); + + BOOST_TEST_EQ( Y::instances, 2 ); + + r2 = r; + + BOOST_TEST_EQ( Y::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( Y::instances, 0 ); + + { + result const r( 1 ); + result r2( "str" ); + + BOOST_TEST_EQ( Y::instances, 1 ); + + r2 = r; + + BOOST_TEST_EQ( Y::instances, 2 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( Y::instances, 0 ); + + return boost::report_errors(); +} diff --git a/test/result_copy_construct.cpp b/test/result_copy_construct.cpp new file mode 100644 index 0000000..bd9a5b6 --- /dev/null +++ b/test/result_copy_construct.cpp @@ -0,0 +1,149 @@ +// Copyright 2017, 2021 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +using namespace boost::result; + +struct X +{ + static int instances; + + int v_; + + X(): v_() { ++instances; } + + explicit X( int v ): v_( v ) { ++instances; } + + X( int v1, int v2 ): v_( v1+v2 ) { ++instances; } + X( int v1, int v2, int v3 ): v_( v1+v2+v3 ) { ++instances; } + + X( X const& r ): v_( r.v_ ) { ++instances; } + + X& operator=( X const& ) = delete; + + ~X() { --instances; } +}; + +bool operator==( X const & x1, X const & x2 ) +{ + return x1.v_ == x2.v_; +} + +std::ostream& operator<<( std::ostream& os, X const & x ) +{ + os << "X:" << x.v_; + return os; +} + +int X::instances = 0; + +int main() +{ + { + result r; + result r2( r ); + + BOOST_TEST_EQ( r, r2 ); + } + + { + result const r; + result r2( r ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r; + result r2( r ); + + BOOST_TEST_EQ( r, r2 ); + BOOST_TEST_EQ( X::instances, 2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2( r ); + + BOOST_TEST_EQ( r, r2 ); + } + + { + result const r( 1 ); + result r2( r ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2( r ); + + BOOST_TEST_EQ( r, r2 ); + BOOST_TEST_EQ( X::instances, 2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result const r( 1 ); + result r2( r ); + + BOOST_TEST_EQ( r, r2 ); + BOOST_TEST_EQ( X::instances, 2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2( r ); + + BOOST_TEST_EQ( r, r2 ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result const r( ec ); + result r2( r ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2( r ); + + BOOST_TEST_EQ( r, r2 ); + BOOST_TEST_EQ( X::instances, 2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result const r( 1 ); + result r2( r ); + + BOOST_TEST_EQ( r, r2 ); + BOOST_TEST_EQ( X::instances, 2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + return boost::report_errors(); +} diff --git a/test/result_default_construct.cpp b/test/result_default_construct.cpp new file mode 100644 index 0000000..134e526 --- /dev/null +++ b/test/result_default_construct.cpp @@ -0,0 +1,34 @@ +// Copyright 2017, 2021 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +using namespace boost::result; + +struct X +{ +}; + +int main() +{ + { + result r; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value(), 0 ); + } + + { + result r; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + } + + return boost::report_errors(); +} diff --git a/test/result_eq.cpp b/test/result_eq.cpp new file mode 100644 index 0000000..d0c1ac6 --- /dev/null +++ b/test/result_eq.cpp @@ -0,0 +1,138 @@ +// Copyright 2017, 2021 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include + +using namespace boost::result; + +struct X +{ + static int instances; + + int v_; + + explicit X( int v ): v_( v ) { ++instances; } + + X( X const& r ) = delete; + X( X&& r ): v_( r.v_ ) { r.v_ = 0; ++instances; } + + X& operator=( X const& ) = delete; + + X& operator=( X&& r ) + { + v_ = r.v_; + r.v_ = 0; + + return *this; + } + + ~X() { --instances; } +}; + +bool operator==( X const & x1, X const & x2 ) +{ + return x1.v_ == x2.v_; +} + +std::ostream& operator<<( std::ostream& os, X const & x ) +{ + os << "X:" << x.v_; + return os; +} + +int X::instances = 0; + +struct Y +{ + static int instances; + + int v_; + + explicit Y( int v = 0 ): v_( v ) { ++instances; } + + Y( Y const& r ) noexcept: v_( r.v_ ) { ++instances; } + Y( Y&& r ) noexcept: v_( r.v_ ) { r.v_ = 0; ++instances; } + + Y& operator=( Y const& ) = default; + + Y& operator=( Y&& r ) + { + v_ = r.v_; + r.v_ = 0; + + return *this; + } + + ~Y() { --instances; } +}; + +bool operator==( Y const & y1, Y const & y2 ) +{ + return y1.v_ == y2.v_; +} + +std::ostream& operator<<( std::ostream& os, Y const & y ) +{ + os << "Y:" << y.v_; + return os; +} + +int Y::instances = 0; + +int main() +{ + { + result r1( 1 ); + result r2( 2 ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + + { + result r1( 1, std::generic_category() ); + result r2( 2, std::generic_category() ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + + { + result r1( 1 ); + result r2( 2, std::generic_category() ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + + { + result r1( in_place_value, 1 ); + result r2( in_place_value, 2 ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + + { + result r1( in_place_error, 1 ); + result r2( in_place_error, 2 ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + + { + result r1( in_place_value, 1 ); + result r2( in_place_error, 2 ); + + BOOST_TEST_EQ( r1, r1 ); + BOOST_TEST_NE( r1, r2 ); + } + + return boost::report_errors(); +} diff --git a/test/result_error_access.cpp b/test/result_error_access.cpp new file mode 100644 index 0000000..b035dd6 --- /dev/null +++ b/test/result_error_access.cpp @@ -0,0 +1,156 @@ +// Copyright 2017, 2021 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include + +using namespace boost::result; + +struct X +{ + int v_; + + explicit X( int v = 0 ): v_( v ) {} + + X( X const& ) = default; + X& operator=( X const& ) = delete; +}; + +int main() +{ + { + result r; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.error(), std::error_code() ); + } + + { + result const r; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.error(), std::error_code() ); + } + + { + BOOST_TEST( result().has_value() ); + BOOST_TEST( !result().has_error() ); + + BOOST_TEST_EQ( result().error(), std::error_code() ); + } + + { + result r( 1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.error(), std::error_code() ); + } + + { + result const r( 1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.error(), std::error_code() ); + } + + { + BOOST_TEST( result( 1 ).has_value() ); + BOOST_TEST( !result( 1 ).has_error() ); + + BOOST_TEST_EQ( result( 1 ).error(), std::error_code() ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), ec ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result const r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), ec ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + BOOST_TEST( !result( ec ).has_value() ); + BOOST_TEST( result( ec ).has_error() ); + + BOOST_TEST_EQ( result( ec ).error(), ec ); + } + + { + result r( 1 ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 1 ); + } + + { + result const r( 1 ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 1 ); + } + + { + BOOST_TEST(( !result( 1 ).has_value() )); + BOOST_TEST(( result( 1 ).has_error() )); + + BOOST_TEST_EQ( (result( 1 ).error().v_), 1 ); + } + + { + result r( "s" ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 0 ); + } + + { + result const r( "s" ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 0 ); + } + + { + BOOST_TEST(( result( "s" ).has_value() )); + BOOST_TEST(( !result( "s" ).has_error() )); + + BOOST_TEST_EQ( (result( "s" ).error().v_), 0 ); + } + + return boost::report_errors(); +} diff --git a/test/result_error_construct.cpp b/test/result_error_construct.cpp new file mode 100644 index 0000000..c96b9f8 --- /dev/null +++ b/test/result_error_construct.cpp @@ -0,0 +1,155 @@ +// Copyright 2017, 2021 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 + +using namespace boost::result; + +struct X +{ + static int instances; + + int v_; + + X(): v_() { ++instances; } + + explicit X( int v ): v_( v ) { ++instances; } + + X( int v1, int v2 ): v_( v1+v2 ) { ++instances; } + X( int v1, int v2, int v3 ): v_( v1+v2+v3 ) { ++instances; } + + X( X const& r ): v_( r.v_ ) { ++instances; } + + X& operator=( X const& ) = delete; + + ~X() { --instances; } +}; + +int X::instances = 0; + +int main() +{ + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), ec ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r = ec; + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), ec ); + } + + { + result r( EINVAL, std::generic_category() ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), std::error_code( EINVAL, std::generic_category() ) ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( in_place_error, ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), ec ); + } + + { + result r( in_place_error, EINVAL, std::generic_category() ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error(), std::error_code( EINVAL, std::generic_category() ) ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1, 2 ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 1+2 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1, 2, 3 ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 1+2+3 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( in_place_error, 1 ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + BOOST_TEST_TRAIT_TRUE((std::is_constructible, std::error_code>)); + BOOST_TEST_TRAIT_TRUE((std::is_convertible>)); + + BOOST_TEST_TRAIT_TRUE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + } + + return boost::report_errors(); +} diff --git a/test/result_move_assign.cpp b/test/result_move_assign.cpp new file mode 100644 index 0000000..43ac62f --- /dev/null +++ b/test/result_move_assign.cpp @@ -0,0 +1,441 @@ +// Copyright 2017, 2021 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 + +using namespace boost::result; + +struct X +{ + static int instances; + + int v_; + + explicit X( int v = 0 ): v_( v ) { ++instances; } + + X( X const& r ) = delete; + X( X&& r ): v_( r.v_ ) { r.v_ = 0; ++instances; } + + X& operator=( X const& ) = delete; + + X& operator=( X&& r ) + { + v_ = r.v_; + r.v_ = 0; + + return *this; + } + + ~X() { --instances; } +}; + +bool operator==( X const & x1, X const & x2 ) +{ + return x1.v_ == x2.v_; +} + +std::ostream& operator<<( std::ostream& os, X const & x ) +{ + os << "X:" << x.v_; + return os; +} + +int X::instances = 0; + +struct Y +{ + static int instances; + + int v_; + + explicit Y( int v = 0 ): v_( v ) { ++instances; } + + Y( Y const& r ) noexcept: v_( r.v_ ) { ++instances; } + Y( Y&& r ) noexcept: v_( r.v_ ) { r.v_ = 0; ++instances; } + + Y& operator=( Y const& ) = default; + + Y& operator=( Y&& r ) + { + v_ = r.v_; + r.v_ = 0; + + return *this; + } + + ~Y() { --instances; } +}; + +bool operator==( Y const & y1, Y const & y2 ) +{ + return y1.v_ == y2.v_; +} + +std::ostream& operator<<( std::ostream& os, Y const & y ) +{ + os << "Y:" << y.v_; + return os; +} + +int Y::instances = 0; + +int main() +{ + // default-initialized lhs + + { + result r; + result r2; + + r2 = std::move( r ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 0 ); + } + + { + result r; + result r2( 1 ); + + r2 = std::move( r ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 0 ); + } + + { + result r; + result r2( ENOENT, std::generic_category() ); + + r2 = std::move( r ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 0 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r; + result r2; + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = std::move( r ); + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), X() ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r; + result r2( 1 ); + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = std::move( r ); + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), X() ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r; + result r2( ENOENT, std::generic_category() ); + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = std::move( r ); + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), X() ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + // value lhs + + { + result r( 1 ); + result r2; + + r2 = std::move( r ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 1 ); + + BOOST_TEST_EQ( r, r2 ); + } + + { + result r( 1 ); + result r2( 2 ); + + r2 = std::move( r ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 1 ); + + BOOST_TEST_EQ( r, r2 ); + } + + { + result r( 1 ); + result r2( ENOENT, std::generic_category() ); + + r2 = std::move( r ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 1 ); + + BOOST_TEST_EQ( r, r2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2; + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = std::move( r ); + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value().v_, 1 ); + + BOOST_TEST_EQ( r.value().v_, 0 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2( 2 ); + + BOOST_TEST_EQ( X::instances, 2 ); + + r2 = std::move( r ); + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value().v_, 1 ); + + BOOST_TEST_EQ( r.value().v_, 0 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2( ENOENT, std::generic_category() ); + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = std::move( r ); + + BOOST_TEST_EQ( X::instances, 2 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value().v_, 1 ); + + BOOST_TEST_EQ( r.value().v_, 0 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + // error lhs + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2; + + r2 = std::move( r ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2( 1 ); + + r2 = std::move( r ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2( ENOENT, std::generic_category() ); + + r2 = std::move( r ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2; + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = std::move( r ); + + BOOST_TEST_EQ( X::instances, 0 ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2( 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + + r2 = std::move( r ); + + BOOST_TEST_EQ( X::instances, 0 ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2( ENOENT, std::generic_category() ); + + BOOST_TEST_EQ( X::instances, 0 ); + + r2 = std::move( r ); + + BOOST_TEST_EQ( X::instances, 0 ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + // + + BOOST_TEST_EQ( Y::instances, 0 ); + + { + result r( 1 ); + result r2( 2 ); + + BOOST_TEST_EQ( Y::instances, 2 ); + + r2 = std::move( r ); + + BOOST_TEST_EQ( Y::instances, 2 ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error().v_, 1 ); + + BOOST_TEST_EQ( r.error().v_, 0 ); + } + + BOOST_TEST_EQ( Y::instances, 0 ); + + { + result r( 1 ); + result r2( "str" ); + + BOOST_TEST_EQ( Y::instances, 1 ); + + r2 = std::move( r ); + + BOOST_TEST_EQ( Y::instances, 2 ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error().v_, 1 ); + + BOOST_TEST_EQ( r.error().v_, 0 ); + } + + BOOST_TEST_EQ( Y::instances, 0 ); + + return boost::report_errors(); +} diff --git a/test/result_move_construct.cpp b/test/result_move_construct.cpp new file mode 100644 index 0000000..08459e5 --- /dev/null +++ b/test/result_move_construct.cpp @@ -0,0 +1,211 @@ +// Copyright 2017, 2021 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +using namespace boost::result; + +struct X +{ + static int instances; + + int v_; + + X(): v_() { ++instances; } + + explicit X( int v ): v_( v ) { ++instances; } + + X( int v1, int v2 ): v_( v1+v2 ) { ++instances; } + X( int v1, int v2, int v3 ): v_( v1+v2+v3 ) { ++instances; } + + X( X const& r ): v_( r.v_ ) { ++instances; } + X( X&& r ): v_( r.v_ ) { r.v_ = 0; ++instances; } + + X& operator=( X const& ) = delete; + + ~X() { --instances; } +}; + +bool operator==( X const & x1, X const & x2 ) +{ + return x1.v_ == x2.v_; +} + +std::ostream& operator<<( std::ostream& os, X const & x ) +{ + os << "X:" << x.v_; + return os; +} + +int X::instances = 0; + +int main() +{ + { + result r; + result r2( std::move( r ) ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 0 ); + } + + { + result r2( result{} ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 0 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r; + result r2( std::move( r ) ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), X() ); + + BOOST_TEST_EQ( X::instances, 2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r2( result{} ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), X() ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2( std::move( r ) ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value(), 1 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 1 ); + } + + { + result r2( result( 1 ) ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value(), 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2( std::move( r ) ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value().v_, 0 ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r2( result( 1 ) ); + + BOOST_TEST( r2.has_value() ); + BOOST_TEST( !r2.has_error() ); + + BOOST_TEST_EQ( r2.value().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + result r2( std::move( r ) ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r2( result{ ec } ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error(), ec ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + result r2( std::move( r ) ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_EQ( r.error().v_, 0 ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r2( result( 1 ) ); + + BOOST_TEST( !r2.has_value() ); + BOOST_TEST( r2.has_error() ); + + BOOST_TEST_EQ( r2.error().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + return boost::report_errors(); +} diff --git a/test/result_swap.cpp b/test/result_swap.cpp new file mode 100644 index 0000000..539f7d6 --- /dev/null +++ b/test/result_swap.cpp @@ -0,0 +1,219 @@ +// Copyright 2017, 2021 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include + +using namespace boost::result; + +struct X +{ + static int instances; + + int v_; + + explicit X( int v ): v_( v ) { ++instances; } + + X( X const& r ) = delete; + X( X&& r ): v_( r.v_ ) { r.v_ = 0; ++instances; } + + X& operator=( X const& ) = delete; + + X& operator=( X&& r ) + { + v_ = r.v_; + r.v_ = 0; + + return *this; + } + + ~X() { --instances; } +}; + +bool operator==( X const & x1, X const & x2 ) +{ + return x1.v_ == x2.v_; +} + +std::ostream& operator<<( std::ostream& os, X const & x ) +{ + os << "X:" << x.v_; + return os; +} + +int X::instances = 0; + +struct Y +{ + static int instances; + + int v_; + + explicit Y( int v = 0 ): v_( v ) { ++instances; } + + Y( Y const& r ) noexcept: v_( r.v_ ) { ++instances; } + Y( Y&& r ) noexcept: v_( r.v_ ) { r.v_ = 0; ++instances; } + + Y& operator=( Y const& ) = default; + + Y& operator=( Y&& r ) + { + v_ = r.v_; + r.v_ = 0; + + return *this; + } + + ~Y() { --instances; } +}; + +bool operator==( Y const & y1, Y const & y2 ) +{ + return y1.v_ == y2.v_; +} + +std::ostream& operator<<( std::ostream& os, Y const & y ) +{ + os << "Y:" << y.v_; + return os; +} + +int Y::instances = 0; + +int main() +{ + { + result r1( 1 ), r1c( r1 ); + result r2( 2 ), r2c( r2 ); + + r1.swap( r2 ); + + BOOST_TEST_EQ( r1, r2c ); + BOOST_TEST_EQ( r2, r1c ); + + swap( r1, r2 ); + + BOOST_TEST_EQ( r1, r1c ); + BOOST_TEST_EQ( r2, r2c ); + } + + { + result r1( 1, std::generic_category() ), r1c( r1 ); + result r2( 2, std::generic_category() ), r2c( r2 ); + + r1.swap( r2 ); + + BOOST_TEST_EQ( r1, r2c ); + BOOST_TEST_EQ( r2, r1c ); + + swap( r1, r2 ); + + BOOST_TEST_EQ( r1, r1c ); + BOOST_TEST_EQ( r2, r2c ); + } + + { + result r1( 1 ), r1c( r1 ); + result r2( 2, std::generic_category() ), r2c( r2 ); + + r1.swap( r2 ); + + BOOST_TEST_EQ( r1, r2c ); + BOOST_TEST_EQ( r2, r1c ); + + swap( r1, r2 ); + + BOOST_TEST_EQ( r1, r1c ); + BOOST_TEST_EQ( r2, r2c ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + BOOST_TEST_EQ( Y::instances, 0 ); + + { + result r1( in_place_value, 1 ), r1c( in_place_value, 1 ); + result r2( in_place_value, 2 ), r2c( in_place_value, 2 ); + + BOOST_TEST_EQ( X::instances, 4 ); + BOOST_TEST_EQ( Y::instances, 0 ); + + r1.swap( r2 ); + + BOOST_TEST_EQ( r1, r2c ); + BOOST_TEST_EQ( r2, r1c ); + + BOOST_TEST_EQ( X::instances, 4 ); + BOOST_TEST_EQ( Y::instances, 0 ); + + swap( r1, r2 ); + + BOOST_TEST_EQ( r1, r1c ); + BOOST_TEST_EQ( r2, r2c ); + + BOOST_TEST_EQ( X::instances, 4 ); + BOOST_TEST_EQ( Y::instances, 0 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + BOOST_TEST_EQ( Y::instances, 0 ); + + { + result r1( in_place_error, 1 ), r1c( in_place_error, 1 ); + result r2( in_place_error, 2 ), r2c( in_place_error, 2 ); + + BOOST_TEST_EQ( X::instances, 0 ); + BOOST_TEST_EQ( Y::instances, 4 ); + + r1.swap( r2 ); + + BOOST_TEST_EQ( r1, r2c ); + BOOST_TEST_EQ( r2, r1c ); + + BOOST_TEST_EQ( X::instances, 0 ); + BOOST_TEST_EQ( Y::instances, 4 ); + + swap( r1, r2 ); + + BOOST_TEST_EQ( r1, r1c ); + BOOST_TEST_EQ( r2, r2c ); + + BOOST_TEST_EQ( X::instances, 0 ); + BOOST_TEST_EQ( Y::instances, 4 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + BOOST_TEST_EQ( Y::instances, 0 ); + + { + result r1( in_place_value, 1 ), r1c( in_place_value, 1 ); + result r2( in_place_error, 2 ), r2c( in_place_error, 2 ); + + BOOST_TEST_EQ( X::instances, 2 ); + BOOST_TEST_EQ( Y::instances, 2 ); + + r1.swap( r2 ); + + BOOST_TEST_EQ( r1, r2c ); + BOOST_TEST_EQ( r2, r1c ); + + BOOST_TEST_EQ( X::instances, 2 ); + BOOST_TEST_EQ( Y::instances, 2 ); + + swap( r1, r2 ); + + BOOST_TEST_EQ( r1, r1c ); + BOOST_TEST_EQ( r2, r2c ); + + BOOST_TEST_EQ( X::instances, 2 ); + BOOST_TEST_EQ( Y::instances, 2 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + BOOST_TEST_EQ( Y::instances, 0 ); + + return boost::report_errors(); +} diff --git a/test/result_value_access.cpp b/test/result_value_access.cpp new file mode 100644 index 0000000..d3e1abe --- /dev/null +++ b/test/result_value_access.cpp @@ -0,0 +1,259 @@ +// Copyright 2017, 2021 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +using namespace boost::result; + +struct X +{ + int v_; + + explicit X( int v ): v_( v ) {} + + X( X const& ) = delete; + X& operator=( X const& ) = delete; +}; + +struct Y +{ +}; + +struct E +{ +}; + +BOOST_NORETURN void throw_exception_from_error_code( Y const & ) +{ + throw E(); +} + +int main() +{ + { + result r; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST( r ); + BOOST_TEST_NOT( !r ); + + BOOST_TEST_EQ( r.value(), 0 ); + BOOST_TEST_EQ( *r, 0 ); + + BOOST_TEST_EQ( r.operator->(), &*r ); + } + + { + result const r; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST( r ); + BOOST_TEST_NOT( !r ); + + BOOST_TEST_EQ( r.value(), 0 ); + BOOST_TEST_EQ( *r, 0 ); + + BOOST_TEST_EQ( r.operator->(), &*r ); + } + + { + BOOST_TEST( result().has_value() ); + BOOST_TEST( !result().has_error() ); + + BOOST_TEST( result() ); + BOOST_TEST_NOT( !result() ); + + BOOST_TEST_EQ( result().value(), 0 ); + BOOST_TEST_EQ( *result(), 0 ); + + BOOST_TEST( result().operator->() != 0 ); + } + + { + result r( 1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST( r ); + BOOST_TEST_NOT( !r ); + + BOOST_TEST_EQ( r.value(), 1 ); + BOOST_TEST_EQ( *r, 1 ); + + BOOST_TEST_EQ( r.operator->(), &*r ); + } + + { + result const r( 1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST( r ); + BOOST_TEST_NOT( !r ); + + BOOST_TEST_EQ( r.value(), 1 ); + BOOST_TEST_EQ( *r, 1 ); + + BOOST_TEST_EQ( r.operator->(), &*r ); + } + + { + BOOST_TEST( result( 1 ).has_value() ); + BOOST_TEST( !result( 1 ).has_error() ); + + BOOST_TEST( result( 1 ) ); + BOOST_TEST_NOT( !result( 1 ) ); + + BOOST_TEST_EQ( result( 1 ).value(), 1 ); + BOOST_TEST_EQ( *result( 1 ), 1 ); + + BOOST_TEST( result( 1 ).operator->() != 0 ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_NOT( r ); + BOOST_TEST( !r ); + + BOOST_TEST_THROWS( r.value(), std::system_error ); + + BOOST_TEST_EQ( r.operator->(), static_cast(0) ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + result const r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_NOT( r ); + BOOST_TEST( !r ); + + BOOST_TEST_THROWS( r.value(), std::system_error ); + + BOOST_TEST_EQ( r.operator->(), static_cast(0) ); + } + + { + auto ec = make_error_code( std::errc::invalid_argument ); + + BOOST_TEST( !result( ec ).has_value() ); + BOOST_TEST( result( ec ).has_error() ); + + BOOST_TEST_NOT( result( ec ) ); + BOOST_TEST( !result( ec ) ); + + BOOST_TEST_THROWS( result( ec ).value(), std::system_error ); + + BOOST_TEST_EQ( result( ec ).operator->(), static_cast(0) ); + } + + { + result r( 1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST( r ); + BOOST_TEST_NOT( !r ); + + BOOST_TEST_EQ( r.value().v_, 1 ); + BOOST_TEST_EQ( (*r).v_, 1 ); + BOOST_TEST_EQ( r->v_, 1 ); + + BOOST_TEST_EQ( r.operator->(), &*r ); + } + + { + result const r( 1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST( r ); + BOOST_TEST_NOT( !r ); + + BOOST_TEST_EQ( r.value().v_, 1 ); + BOOST_TEST_EQ( (*r).v_, 1 ); + BOOST_TEST_EQ( r->v_, 1 ); + + BOOST_TEST_EQ( r.operator->(), &*r ); + } + + { + BOOST_TEST( result( 1 ).has_value() ); + BOOST_TEST( !result( 1 ).has_error() ); + + BOOST_TEST( result( 1 ) ); + BOOST_TEST_NOT( !result( 1 ) ); + + BOOST_TEST_EQ( result( 1 ).value().v_, 1 ); + BOOST_TEST_EQ( (*result( 1 )).v_, 1 ); + BOOST_TEST_EQ( result( 1 )->v_, 1 ); + } + + { + auto ec = Y(); + + result r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_NOT( r ); + BOOST_TEST( !r ); + + BOOST_TEST_THROWS( r.value(), E ); + + BOOST_TEST_EQ( r.operator->(), static_cast(0) ); + } + + { + auto ec = Y(); + + result const r( ec ); + + BOOST_TEST( !r.has_value() ); + BOOST_TEST( r.has_error() ); + + BOOST_TEST_NOT( r ); + BOOST_TEST( !r ); + + BOOST_TEST_THROWS( r.value(), E ); + + BOOST_TEST_EQ( r.operator->(), static_cast(0) ); + } + + { + auto ec = Y(); + + BOOST_TEST(( !result( ec ).has_value() )); + BOOST_TEST(( result( ec ).has_error() )); + + BOOST_TEST_NOT(( result( ec ) )); + BOOST_TEST(( !result( ec ) )); + + BOOST_TEST_THROWS( (result( ec ).value()), E ); + + BOOST_TEST_EQ( (result( ec ).operator->()), static_cast(0) ); + } + + return boost::report_errors(); +} diff --git a/test/result_value_construct.cpp b/test/result_value_construct.cpp new file mode 100644 index 0000000..7e61934 --- /dev/null +++ b/test/result_value_construct.cpp @@ -0,0 +1,125 @@ +// Copyright 2017, 2021 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +using namespace boost::result; + +struct X +{ + static int instances; + + int v_; + + explicit X( int v ): v_( v ) { ++instances; } + + X( int v1, int v2 ): v_( v1+v2 ) { ++instances; } + X( int v1, int v2, int v3 ): v_( v1+v2+v3 ) { ++instances; } + + X( X const& ) = delete; + X& operator=( X const& ) = delete; + + ~X() { --instances; } +}; + +int X::instances = 0; + +int main() +{ + { + result r( 0 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value(), 0 ); + } + + { + result r = 0; + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value(), 0 ); + } + + { + result r( in_place_value, 1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( *r, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value().v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1, 2 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value().v_, 1+2 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( 1, 2, 3 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r.value().v_, 1+2+3 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + result r( in_place_value, 1 ); + + BOOST_TEST( r.has_value() ); + BOOST_TEST( !r.has_error() ); + + BOOST_TEST_EQ( r->v_, 1 ); + + BOOST_TEST_EQ( X::instances, 1 ); + } + + BOOST_TEST_EQ( X::instances, 0 ); + + { + BOOST_TEST_TRAIT_TRUE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_TRUE((std::is_convertible>)); + + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, int>)); + + BOOST_TEST_TRAIT_TRUE((std::is_constructible, int>)); + BOOST_TEST_TRAIT_FALSE((std::is_convertible>)); + } + + return boost::report_errors(); +}