Compare commits

...

15 Commits

Author SHA1 Message Date
Peter Dimov
f332a52597 Disable C4800 under msvc-14.0 2023-01-22 04:54:46 +02:00
Peter Dimov
c92d50abbd Do not consider types with explicit operator bool (such as result itself) constructible from bool for the purposes of result construction. Refs #104. 2023-01-22 02:07:28 +02:00
Peter Dimov
805b260a7a Add test/result_value_construct5.cpp. Refs #104. 2023-01-22 01:58:29 +02:00
Peter Dimov
f32ffcba48 Update result_value_construct4.cpp 2023-01-22 01:25:30 +02:00
Peter Dimov
8ce2a9f835 Disable result converting constructor when T is convertible from the rhs result<T2, E2>. Refs #104. 2023-01-22 01:22:02 +02:00
Peter Dimov
6a58b03eab Add test/result_value_construct4.cpp. Refs #104. 2023-01-22 01:15:08 +02:00
Peter Dimov
f0b27c5826 Enable implicit construction when the alternative is explicitly constructible from the argument. Fixes #103. 2023-01-21 20:09:53 +02:00
Peter Dimov
456b3c2dad Add test/result_error_construct4.cpp. Refs #103. 2023-01-21 19:45:32 +02:00
Peter Dimov
eb3f3a8e41 Use boost::core::snprintf in std_interop_test16 as well 2023-01-20 04:39:08 +02:00
Peter Dimov
e6986a51d5 Merge branch 'develop' into feature/issue-102 2023-01-20 04:38:15 +02:00
Peter Dimov
71ee26c188 Move the stdcat mutex into init_stdcat() as a local static to fix msvc-12.0 2023-01-20 01:22:42 +02:00
Peter Dimov
8449c62162 Update detail/mutex.hpp to use std::shared_mutex under the MS STL 2023-01-19 18:05:21 +02:00
Peter Dimov
4bca94ffc4 Merge branch 'develop' into feature/issue-102 2023-01-19 16:35:05 +02:00
Peter Dimov
86ff47ff63 Update std_interop_test16.cpp to not use asio/error.hpp. 2023-01-19 11:13:40 +02:00
Peter Dimov
06ddfdb4a6 Add std_interop_test16.cpp. Refs #102. 2023-01-19 05:46:11 +02:00
10 changed files with 314 additions and 23 deletions

View File

@@ -106,18 +106,6 @@ namespace boost
namespace system
{
namespace detail
{
template<class = void> struct stdcat_mx_holder
{
static mutex mx_;
};
template<class T> mutex stdcat_mx_holder<T>::mx_;
} // namespace detail
inline void error_category::init_stdcat() const
{
static_assert( sizeof( stdcat_ ) >= sizeof( boost::system::detail::std_category ), "sizeof(stdcat_) is not enough for std_category" );
@@ -130,7 +118,13 @@ inline void error_category::init_stdcat() const
#endif
system::detail::lock_guard<system::detail::mutex> lk( system::detail::stdcat_mx_holder<>::mx_ );
// detail::mutex has a constexpr default constructor,
// and therefore guarantees static initialization, on
// everything except VS 2013 (msvc-12.0)
static system::detail::mutex mx_;
system::detail::lock_guard<system::detail::mutex> lk( mx_ );
if( sc_init_.load( std::memory_order_acquire ) == 0 )
{

View File

@@ -31,6 +31,28 @@ struct mutex
} // namespace system
} // namespace boost
#elif defined(BOOST_MSSTL_VERSION) && BOOST_MSSTL_VERSION >= 140
// Under the MS STL, std::mutex::mutex() is not constexpr, as is
// required by the standard, which leads to initialization order
// issues. However, shared_mutex is based on SRWLock and its
// default constructor is constexpr, so we use that instead.
#include <shared_mutex>
namespace boost
{
namespace system
{
namespace detail
{
typedef std::shared_mutex mutex;
} // namespace detail
} // namespace system
} // namespace boost
#else
#include <mutex>

View File

@@ -85,6 +85,10 @@ template<class T> using remove_cvref = typename std::remove_cv< typename std::re
template<class... T> using is_errc_t = std::is_same<mp11::mp_list<remove_cvref<T>...>, mp11::mp_list<errc::errc_t>>;
template<class T, class... A> struct is_constructible: std::is_constructible<T, A...> {};
template<class A> struct is_constructible<bool, A>: std::is_convertible<A, bool> {};
template<class A> struct is_constructible<bool const, A>: std::is_convertible<A, bool> {};
} // namespace detail
// result
@@ -122,7 +126,7 @@ public:
template<class A = T, typename std::enable_if<
std::is_convertible<A, T>::value &&
!(detail::is_errc_t<A>::value && std::is_arithmetic<T>::value) &&
!std::is_constructible<E, A>::value, int>::type = 0>
!std::is_convertible<A, E>::value, int>::type = 0>
constexpr result( A&& a )
noexcept( std::is_nothrow_constructible<T, A>::value )
: v_( in_place_value, std::forward<A>(a) )
@@ -132,7 +136,7 @@ public:
// implicit, error
template<class A = E, class = void, typename std::enable_if<
std::is_convertible<A, E>::value &&
!std::is_constructible<T, A>::value, int>::type = 0>
!std::is_convertible<A, T>::value, int>::type = 0>
constexpr result( A&& a )
noexcept( std::is_nothrow_constructible<E, A>::value )
: v_( in_place_error, std::forward<A>(a) )
@@ -141,9 +145,9 @@ public:
// explicit, value
template<class... A, class En = typename std::enable_if<
std::is_constructible<T, A...>::value &&
detail::is_constructible<T, A...>::value &&
!(detail::is_errc_t<A...>::value && std::is_arithmetic<T>::value) &&
!std::is_constructible<E, A...>::value &&
!detail::is_constructible<E, A...>::value &&
sizeof...(A) >= 1
>::type>
explicit constexpr result( A&&... a )
@@ -154,8 +158,8 @@ public:
// explicit, error
template<class... A, class En2 = void, class En = typename std::enable_if<
!std::is_constructible<T, A...>::value &&
std::is_constructible<E, A...>::value &&
!detail::is_constructible<T, A...>::value &&
detail::is_constructible<E, A...>::value &&
sizeof...(A) >= 1
>::type>
explicit constexpr result( A&&... a )
@@ -187,7 +191,8 @@ public:
// converting
template<class T2, class E2, class En = typename std::enable_if<
std::is_convertible<T2, T>::value &&
std::is_convertible<E2, E>::value
std::is_convertible<E2, E>::value &&
!std::is_convertible<result<T2, E2> const&, T>::value
>::type>
BOOST_CXX14_CONSTEXPR result( result<T2, E2> const& r2 )
noexcept(
@@ -205,7 +210,8 @@ public:
template<class T2, class E2, class En = typename std::enable_if<
std::is_convertible<T2, T>::value &&
std::is_convertible<E2, E>::value
std::is_convertible<E2, E>::value &&
!std::is_convertible<result<T2, E2>&&, T>::value
>::type>
BOOST_CXX14_CONSTEXPR result( result<T2, E2>&& r2 )
noexcept(

View File

@@ -134,6 +134,8 @@ boost_test(TYPE run SOURCES win32_generic_test.cpp)
boost_test(TYPE run SOURCES ec_hash_value_test.cpp)
boost_test(TYPE run SOURCES std_interop_test16.cpp)
# result
set(BOOST_TEST_COMPILE_FEATURES cxx_std_11)
@@ -152,7 +154,12 @@ boost_test(TYPE run SOURCES result_eq.cpp)
boost_test(TYPE run SOURCES result_range_for.cpp)
boost_test(TYPE run SOURCES result_value_construct2.cpp)
boost_test(TYPE run SOURCES result_error_construct2.cpp)
boost_test(TYPE run SOURCES result_errc_construct.cpp)
boost_test(TYPE run SOURCES result_convert_construct.cpp)
boost_test(TYPE run SOURCES result_typedefs.cpp)
boost_test(TYPE run SOURCES result_value_construct3.cpp)
boost_test(TYPE run SOURCES result_error_construct3.cpp)
boost_test(TYPE run SOURCES result_emplace.cpp)
boost_test(TYPE run SOURCES result_error_construct4.cpp)
boost_test(TYPE run SOURCES result_value_construct4.cpp)
boost_test(TYPE run SOURCES result_value_construct5.cpp)

View File

@@ -162,6 +162,8 @@ run win32_generic_test.cpp ;
run ec_hash_value_test.cpp ;
run std_interop_test16.cpp ;
# result
import ../../config/checks/config : requires ;
@@ -188,3 +190,6 @@ run result_typedefs.cpp : : : $(CPP11) ;
run result_value_construct3.cpp : : : $(CPP11) ;
run result_error_construct3.cpp : : : $(CPP11) ;
run result_emplace.cpp : : : $(CPP11) ;
run result_error_construct4.cpp : : : $(CPP11) ;
run result_value_construct4.cpp : : : $(CPP11) ;
run result_value_construct5.cpp : : : $(CPP11) ;

View File

@@ -146,8 +146,14 @@ int main()
BOOST_TEST_TRAIT_TRUE((std::is_constructible<result<std::string, X>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int, result<std::string, X>>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int, X>, int>));
BOOST_TEST_TRAIT_FALSE((std::is_convertible<int, result<int, X>>));
// We'd like this to be false due to the ambiguity caused by X having
// an explicit constructor taking an int, which should be viable in this
// context, but the implicit constructor is enabled, and there's no way to
// disallow it
//
// BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<int, X>, int>));
BOOST_TEST_TRAIT_TRUE((std::is_convertible<int, result<int, X>>));
}
{

View File

@@ -0,0 +1,49 @@
// Copyright 2023 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::system;
// Eigen::Matrix4d has an explicit templated constructor
// https://github.com/boostorg/system/issues/103
// https://github.com/boostorg/json/issues/843
struct X
{
X() {}
template<class T> explicit X( T const& ) {}
};
int main()
{
{
auto ec = make_error_code( errc::invalid_argument );
result<X> r = ec;
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), ec );
}
#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
{
auto ec = make_error_code( std::errc::invalid_argument );
result<X> r = ec;
BOOST_TEST( !r.has_value() );
BOOST_TEST( r.has_error() );
BOOST_TEST_EQ( r.error(), ec );
}
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,59 @@
// Copyright 2023 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::system;
// Tricky mixed construction cases
// https://github.com/boostorg/system/issues/104
// https://brevzin.github.io//c++/2023/01/18/optional-construction/
int main()
{
{
result<int> r( make_error_code( errc::invalid_argument ) );
result<result<int>> r2( r );
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2.value(), r );
}
{
result<int> r( 5 );
result<result<int>> r2( r );
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2.value(), r );
}
{
result<int> const r( make_error_code( errc::invalid_argument ) );
result<result<int>> r2( r );
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2.value(), r );
}
{
result<int> const r( 5 );
result<result<int>> r2( r );
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2.value(), r );
}
{
result<int> r( make_error_code( errc::invalid_argument ) );
result<result<int>> r2( std::move( r ) );
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2.value(), r );
}
{
result<int> r( 5 );
result<result<int>> r2( std::move( r ) );
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2.value(), r );
}
return boost::report_errors();
}

View File

@@ -0,0 +1,86 @@
// Copyright 2023 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(_MSC_VER) && _MSC_VER < 1910
# pragma warning( disable: 4800 ) // forcing value to bool 'true' or 'false'
#endif
#include <boost/system/result.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#include <utility>
#include <type_traits>
using namespace boost::system;
// Tricky mixed construction cases
// https://github.com/boostorg/system/issues/104
// https://brevzin.github.io//c++/2023/01/18/optional-construction/
template<class R1, class R2> void test()
{
{
R1 r1( make_error_code( errc::invalid_argument ) );
R2 r2( r1 );
BOOST_TEST( !r2.has_value() );
}
{
R1 r1( 0 );
R2 r2( r1 );
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2.value(), false );
}
{
R1 r1( 1 );
R2 r2( r1 );
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2.value(), true );
}
{
R1 r1( make_error_code( errc::invalid_argument ) );
R2 r2( std::move( r1 ) );
BOOST_TEST( !r2.has_value() );
}
{
R1 r1( 0 );
R2 r2( std::move( r1 ) );
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2.value(), false );
}
{
R1 r1( 1 );
R2 r2( std::move( r1 ) );
BOOST_TEST( r2.has_value() ) && BOOST_TEST_EQ( r2.value(), true );
}
}
struct X
{
};
int main()
{
test< result<int>, result<bool> >();
test< result<int> const, result<bool> >();
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<bool>, result<X>&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<bool>, result<X> const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<bool>, result<X>&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<bool>, result<X> const&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<bool const>, result<X>&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<bool const>, result<X> const&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<bool const>, result<X>&&>));
BOOST_TEST_TRAIT_FALSE((std::is_constructible<result<bool const>, result<X> const&&>));
return boost::report_errors();
}

View File

@@ -0,0 +1,57 @@
// Copyright 2023 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
#include <boost/system/error_category.hpp>
#include <boost/config/pragma_message.hpp>
#if !defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR)
BOOST_PRAGMA_MESSAGE( "BOOST_SYSTEM_HAS_SYSTEM_ERROR not defined, test will be skipped" )
int main() {}
#else
#include <boost/core/lightweight_test.hpp>
#include <boost/core/snprintf.hpp>
#include <system_error>
// get_user_category
class user_category: public boost::system::error_category
{
public:
virtual const char * name() const BOOST_NOEXCEPT
{
return "user";
}
virtual std::string message( int ev ) const
{
char buffer[ 256 ];
boost::core::snprintf( buffer, sizeof( buffer ), "user message %d", ev );
return buffer;
}
};
boost::system::error_category const & get_user_category()
{
static user_category instance;
return instance;
}
//
bool init_lwt = (boost::core::lwt_init(), true);
std::error_category const & cat = get_user_category();
int main()
{
BOOST_TEST_CSTR_EQ( cat.name(), "user" );
return boost::report_errors();
}
#endif