From a9b64a888a24400cc2af9910a6ff88c3c4fd3210 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 15 Sep 2021 07:03:18 +0300 Subject: [PATCH] Add support for source_location to error_code --- include/boost/system/detail/error_code.hpp | 94 +++++++++++------ test/Jamfile.v2 | 2 + test/ec_location_test.cpp | 116 +++++++++++++++++++++ 3 files changed, 183 insertions(+), 29 deletions(-) create mode 100644 test/ec_location_test.cpp diff --git a/include/boost/system/detail/error_code.hpp b/include/boost/system/detail/error_code.hpp index 5d263b0..e46ffe4 100644 --- a/include/boost/system/detail/error_code.hpp +++ b/include/boost/system/detail/error_code.hpp @@ -20,10 +20,12 @@ #include #include #include +#include #include #include #include #include +#include #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) # include @@ -77,19 +79,20 @@ private: // 1: holds std::error_code in d2_ // 2: holds error code in d1_, failed == false // 3: holds error code in d1_, failed == true - unsigned flags_; + // >3: pointer to source_location, failed_ in lsb + boost::uintptr_t lc_flags_; public: // constructors: BOOST_SYSTEM_CONSTEXPR error_code() BOOST_NOEXCEPT: - d1_(), flags_( 0 ) + d1_(), lc_flags_( 0 ) { } BOOST_SYSTEM_CONSTEXPR error_code( int val, const error_category & cat ) BOOST_NOEXCEPT: - d1_(), flags_( 2 + detail::failed_impl( val, cat ) ) + d1_(), lc_flags_( 2 + detail::failed_impl( val, cat ) ) { d1_.val_ = val; d1_.cat_ = &cat; @@ -101,10 +104,17 @@ public: *this = make_error_code( e ); } + error_code( int val, const error_category & cat, source_location const * loc ) BOOST_NOEXCEPT: + d1_(), lc_flags_( reinterpret_cast( loc ) | +detail::failed_impl( val, cat ) ) + { + d1_.val_ = val; + d1_.cat_ = &cat; + } + #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) error_code( std::error_code const& ec ) BOOST_NOEXCEPT: - flags_( 1 ) + lc_flags_( 1 ) { ::new( d2_ ) std::error_code( ec ); } @@ -118,6 +128,11 @@ public: *this = error_code( val, cat ); } + void assign( int val, const error_category & cat, source_location const * loc ) BOOST_NOEXCEPT + { + *this = error_code( val, cat, loc ); + } + template BOOST_SYSTEM_CONSTEXPR typename detail::enable_if::value, error_code>::type & operator=( ErrorCodeEnum val ) BOOST_NOEXCEPT @@ -135,7 +150,7 @@ public: BOOST_SYSTEM_CONSTEXPR int value() const BOOST_NOEXCEPT { - if( flags_ != 1 ) + if( lc_flags_ != 1 ) { return d1_.val_; } @@ -154,11 +169,11 @@ public: BOOST_SYSTEM_CONSTEXPR const error_category & category() const BOOST_NOEXCEPT { - if( flags_ == 0 ) + if( lc_flags_ == 0 ) { return system_category(); } - else if( flags_ == 1 ) + else if( lc_flags_ == 1 ) { return detail::interop_category(); } @@ -178,7 +193,7 @@ public: { #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) - if( flags_ == 1 ) + if( lc_flags_ == 1 ) { std::error_code const& ec = *reinterpret_cast( d2_ ); return ec.message(); @@ -192,7 +207,7 @@ public: char const * message( char * buffer, std::size_t len ) const BOOST_NOEXCEPT { #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) - if( flags_ == 1 ) + if( lc_flags_ == 1 ) { #if !defined(BOOST_NO_EXCEPTIONS) try @@ -217,7 +232,7 @@ public: { #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) - if( flags_ == 1 ) + if( lc_flags_ == 1 ) { std::error_code const& ec = *reinterpret_cast( d2_ ); return ec.value() != 0; @@ -226,7 +241,7 @@ public: #endif { - return (flags_ & 1) != 0; + return (lc_flags_ & 1) != 0; } } @@ -254,6 +269,17 @@ public: #endif + bool has_location() const BOOST_NOEXCEPT + { + return lc_flags_ >= 4; + } + + source_location const & location() const BOOST_NOEXCEPT + { + BOOST_STATIC_CONSTEXPR source_location loc; + return lc_flags_ >= 4? *reinterpret_cast( lc_flags_ &~ static_cast( 1 ) ): loc; + } + // relationals: // the more symmetrical non-member syntax allows enum @@ -263,7 +289,7 @@ public: { #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) - if( lhs.flags_ == 1 && rhs.flags_ == 1 ) + if( lhs.lc_flags_ == 1 && rhs.lc_flags_ == 1 ) { std::error_code const& e1 = *reinterpret_cast( lhs.d2_ ); std::error_code const& e2 = *reinterpret_cast( rhs.d2_ ); @@ -281,7 +307,7 @@ public: { #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) - if( lhs.flags_ == 1 && rhs.flags_ == 1 ) + if( lhs.lc_flags_ == 1 && rhs.lc_flags_ == 1 ) { std::error_code const& e1 = *reinterpret_cast( lhs.d2_ ); std::error_code const& e2 = *reinterpret_cast( rhs.d2_ ); @@ -304,7 +330,7 @@ public: { #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) - if( code.flags_ == 1 ) + if( code.lc_flags_ == 1 ) { return static_cast( code ) == static_cast( condition ); } @@ -320,7 +346,7 @@ public: { #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) - if( code.flags_ == 1 ) + if( code.lc_flags_ == 1 ) { return static_cast( code ) == static_cast( condition ); } @@ -444,11 +470,11 @@ public: operator std::error_code () const { - if( flags_ == 1 ) + if( lc_flags_ == 1 ) { return *reinterpret_cast( d2_ ); } - else if( flags_ == 0 ) + else if( lc_flags_ == 0 ) { //return std::error_code(); return std::error_code( 0, boost::system::system_category() ); @@ -468,11 +494,11 @@ public: class E = typename detail::enable_if::value>::type> operator T& () { - if( flags_ != 1 ) + if( lc_flags_ != 1 ) { std::error_code e2( *this ); ::new( d2_ ) std::error_code( e2 ); - flags_ = 1; + lc_flags_ = 1; } return *reinterpret_cast( d2_ ); @@ -488,24 +514,34 @@ public: #endif - template - inline friend std::basic_ostream& - operator<< (std::basic_ostream& os, error_code const & ec) + std::string to_string() const { #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) - if( ec.flags_ == 1 ) + if( lc_flags_ == 1 ) { - std::error_code const& e2 = *reinterpret_cast( ec.d2_ ); - os << "std:" << e2.category().name() << ':' << e2.value(); + std::error_code const& e2 = *reinterpret_cast( d2_ ); + + char buffer[ 32 ]; + detail::snprintf( buffer, sizeof( buffer ), "%d", e2.value() ); + + return std::string( "std:" ) + e2.category().name() + ":" + buffer; } else #endif { - os << ec.category().name() << ':' << ec.value(); - } + char buffer[ 32 ]; + detail::snprintf( buffer, sizeof( buffer ), "%d", value() ); - return os; + return std::string( category().name() ) + ":" + buffer; + } + } + + template + inline friend std::basic_ostream& + operator<< (std::basic_ostream& os, error_code const & ec) + { + return os << ec.to_string(); } }; @@ -513,7 +549,7 @@ inline std::size_t hash_value( error_code const & ec ) { #if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) - if( ec.flags_ == 1 ) + if( ec.lc_flags_ == 1 ) { std::error_code const& e2 = *reinterpret_cast( ec.d2_ ); return std::hash()( e2 ); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index e2b0edc..0b7103a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -108,3 +108,5 @@ run std_interop_test6.cpp ; run std_interop_test7.cpp ; run std_interop_test8.cpp ; run std_interop_test9.cpp ; + +run ec_location_test.cpp ; diff --git a/test/ec_location_test.cpp b/test/ec_location_test.cpp new file mode 100644 index 0000000..b46fa62 --- /dev/null +++ b/test/ec_location_test.cpp @@ -0,0 +1,116 @@ +// Copyright 2021 Peter Dimov. +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +int main() +{ + int const val = ENOENT; + boost::system::error_category const & cat = boost::system::generic_category(); + + { + boost::system::error_code ec( val, cat ); + + BOOST_TEST_EQ( ec.value(), val ); + BOOST_TEST_EQ( &ec.category(), &cat ); + + BOOST_TEST( ec.failed() ); + + BOOST_TEST( !ec.has_location() ); + BOOST_TEST_EQ( ec.location().line(), 0 ); + } + + { + BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; + + boost::system::error_code ec( val, cat, &loc ); + + BOOST_TEST_EQ( ec.value(), val ); + BOOST_TEST_EQ( &ec.category(), &cat ); + + BOOST_TEST( ec.failed() ); + + BOOST_TEST( ec.has_location() ); + BOOST_TEST_EQ( ec.location().line(), 27 ); + } + + { + boost::system::error_code ec; + + BOOST_TEST_EQ( ec.value(), 0 ); + BOOST_TEST_EQ( &ec.category(), &boost::system::system_category() ); + + BOOST_TEST( !ec.failed() ); + + BOOST_TEST( !ec.has_location() ); + BOOST_TEST_EQ( ec.location().line(), 0 ); + + BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; + + ec = boost::system::error_code( val, cat, &loc ); + + BOOST_TEST_EQ( ec.value(), val ); + BOOST_TEST_EQ( &ec.category(), &cat ); + + BOOST_TEST( ec.failed() ); + + BOOST_TEST( ec.has_location() ); + BOOST_TEST_EQ( ec.location().line(), 51 ); + } + + { + boost::system::error_code ec; + + BOOST_TEST_EQ( ec.value(), 0 ); + BOOST_TEST_EQ( &ec.category(), &boost::system::system_category() ); + + BOOST_TEST( !ec.failed() ); + + BOOST_TEST( !ec.has_location() ); + BOOST_TEST_EQ( ec.location().line(), 0 ); + + BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; + + ec.assign( val, cat, &loc ); + + BOOST_TEST_EQ( ec.value(), val ); + BOOST_TEST_EQ( &ec.category(), &cat ); + + BOOST_TEST( ec.failed() ); + + BOOST_TEST( ec.has_location() ); + BOOST_TEST_EQ( ec.location().line(), 75 ); + } + +#if defined(BOOST_SYSTEM_HAS_SYSTEM_ERROR) + + { + std::error_code e2( val, std::generic_category() ); + + boost::system::error_code ec( e2 ); + + BOOST_TEST( ec.failed() ); + + BOOST_TEST( !ec.has_location() ); + BOOST_TEST_EQ( ec.location().line(), 0 ); + + BOOST_STATIC_CONSTEXPR boost::source_location loc = BOOST_CURRENT_LOCATION; + + ec.assign( val, cat, &loc ); + + BOOST_TEST_EQ( ec.value(), val ); + BOOST_TEST_EQ( &ec.category(), &cat ); + + BOOST_TEST( ec.failed() ); + + BOOST_TEST( ec.has_location() ); + BOOST_TEST_EQ( ec.location().line(), 100 ); + } + +#endif + + return boost::report_errors(); +}