From e76f4e6325f6529b8f202d531d2afe4e4ce45cb9 Mon Sep 17 00:00:00 2001 From: Emil Dotchevski Date: Tue, 27 Nov 2018 09:15:34 -0800 Subject: [PATCH] e_unexpected_diagnostic_output --- adoc/README.adoc | 40 ++++----- adoc/synopses/common.adoc | 27 +++---- include/boost/leaf/common.hpp | 2 +- include/boost/leaf/detail/print.hpp | 4 +- include/boost/leaf/detail/throw.hpp | 2 +- include/boost/leaf/error.hpp | 121 +++++++++++++++++++--------- test/diagnostic_output_test.cpp | 16 ++-- test/error_test.cpp | 4 +- test/result_test.4.cpp | 10 +-- 9 files changed, 133 insertions(+), 93 deletions(-) diff --git a/adoc/README.adoc b/adoc/README.adoc index 5ac0cda..d85bff9 100644 --- a/adoc/README.adoc +++ b/adoc/README.adoc @@ -1644,7 +1644,7 @@ This exception is thrown by `<>()`/`<> ---- -Effects: :: `LEAF_ERROR(e...)` is equivalent to `leaf::<>(e...)`, except the current source location is automatically passed to the `leaf::error` constructor, in a `<>` object. +Effects: :: `LEAF_ERROR(e...)` is equivalent to `leaf::<>(e...)`, except the current source location is automatically passed to the `leaf::error` constructor, in a `<>` object. NOTE: `LEAF_ERROR` is designed for use in `return` expressions, to automatically communicate the location of the error being reported (but see <>). @@ -1744,7 +1744,7 @@ IMPORTANT: If thrown, a `leaf::<>` can be caught as `Ex #define LEAF_THROW <> ---- -Effects: :: `LEAF_THROW(e...)` is equivalent to `throw leaf::<>(e...)`, except the current source location is automatically passed to the `leaf::exception` constructor, in a `<>` object. +Effects: :: `LEAF_THROW(e...)` is equivalent to `throw leaf::<>(e...)`, except the current source location is automatically passed to the `leaf::exception` constructor, in a `<>` object. ''' @@ -1959,53 +1959,47 @@ TIP: It is usually a logic error to use `e_errno` with <>; it should be ''' [[e_source_location]] -==== `meta::e_source_location` +==== `e_source_location` [source,c++] ---- namespace boost { namespace leaf { - namespace meta + struct e_source_location { - struct e_source_location - { - char const * const file; - int const line; - char const * const function; + char const * const file; + int const line; + char const * const function; - friend std::ostream & operator<<( std::ostream & os, e_source_location const & x ); - }; - } + friend std::ostream & operator<<( std::ostream & os, e_source_location const & x ); + }; } } ---- -The <> and <> macros capture `pass:[__FILE__]`, `pass:[__LINE__]` and `pass:[__FUNCTION__]` into a `meta::e_source_location` object, if there is currently `<>` storage available for it. When `<>` is invoked, all three items are printed. +The <> and <> macros capture `pass:[__FILE__]`, `pass:[__LINE__]` and `pass:[__FUNCTION__]` into a `e_source_location` object, if there is currently `<>` storage available for it. When `<>` is invoked, all three items are printed. ''' [[e_unexpected]] -==== `meta::e_unexpected` +==== `e_unexpected` [source,c++] ---- namespace boost { namespace leaf { - namespace meta + struct e_unexpected { - struct e_unexpected - { - char const * (*first_type)(); - int count; + char const * (*first_type)(); + int count; - friend std::ostream & operator<<( std::ostream & os, e_unexpected const & x ); - }; - } + friend std::ostream & operator<<( std::ostream & os, e_unexpected const & x ); + }; } } ---- -Whenever an error object of unexpected type (a type for which there is currently no `<>` storage available) is passed to the `leaf::error` <> or other similar function, if there is currently `expect` storage available for `meta::e_unexpected`, LEAF will communicate the type of the object in the first such occurrence, as well as the count of these occurrences regardless of type. +Whenever an error object of unexpected type (a type for which there is currently no `<>` storage available) is passed to the `leaf::error` <> or other similar function, if there is currently `expect` storage available for `e_unexpected`, LEAF will communicate the type of the object in the first such occurrence, as well as the count of these occurrences regardless of type. [[techniques]] == Programming Techniques diff --git a/adoc/synopses/common.adoc b/adoc/synopses/common.adoc index 6b42f4c..ba43e4b 100644 --- a/adoc/synopses/common.adoc +++ b/adoc/synopses/common.adoc @@ -12,25 +12,22 @@ namespace boost { namespace leaf { friend std::ostream & operator<<( std::ostream & os, e_errno const & err ); }; - namespace meta + struct e_source_location { - struct e_source_location - { - char const * const file; - int const line; - char const * const function; + char const * const file; + int const line; + char const * const function; - friend std::ostream & operator<<( std::ostream & os, e_source_location const & x ); - }; + friend std::ostream & operator<<( std::ostream & os, e_source_location const & x ); + }; - struct e_unexpected - { - char const * (*first_type)(); - int count; + struct e_unexpected + { + char const * (*first_type)(); + int count; - friend std::ostream & operator<<( std::ostream & os, e_unexpected const & x ); - }; - } + friend std::ostream & operator<<( std::ostream & os, e_unexpected const & x ); + }; } } ---- diff --git a/include/boost/leaf/common.hpp b/include/boost/leaf/common.hpp index 5e07c7f..35dcfa4 100644 --- a/include/boost/leaf/common.hpp +++ b/include/boost/leaf/common.hpp @@ -25,7 +25,7 @@ namespace boost { namespace leaf { friend std::ostream & operator<<( std::ostream & os, e_errno const & err ) { using namespace std; - return os << type() << " = " << err.value << ", \"" << std::strerror(err.value) << '"'; + return os << type() << ": " << err.value << ", \"" << std::strerror(err.value) << '"'; } }; diff --git a/include/boost/leaf/detail/print.hpp b/include/boost/leaf/detail/print.hpp index 1468746..90439d7 100644 --- a/include/boost/leaf/detail/print.hpp +++ b/include/boost/leaf/detail/print.hpp @@ -69,7 +69,7 @@ namespace boost { namespace leaf { { static bool print( std::ostream & os, Wrapper const & x ) { - os << type() << " = " << x.value; + os << type() << ": " << x.value; return true; } }; @@ -79,7 +79,7 @@ namespace boost { namespace leaf { { static bool print( std::ostream & os, Wrapper const & ) { - os << type() << " = N/A"; + os << type() << ": N/A"; return true; } }; diff --git a/include/boost/leaf/detail/throw.hpp b/include/boost/leaf/detail/throw.hpp index 5daaec5..70208d1 100644 --- a/include/boost/leaf/detail/throw.hpp +++ b/include/boost/leaf/detail/throw.hpp @@ -10,7 +10,7 @@ #include #include -#define LEAF_THROW ::boost::leaf::next_error_value().propagate(::boost::leaf::meta::e_source_location{__FILE__,__LINE__,__FUNCTION__}),throw::boost::leaf::exception +#define LEAF_THROW ::boost::leaf::next_error_value().propagate(::boost::leaf::e_source_location{__FILE__,__LINE__,__FUNCTION__}),throw::boost::leaf::exception namespace boost { namespace leaf { diff --git a/include/boost/leaf/error.hpp b/include/boost/leaf/error.hpp index b1b28aa..d03df68 100644 --- a/include/boost/leaf/error.hpp +++ b/include/boost/leaf/error.hpp @@ -15,40 +15,52 @@ #include #include #include +#include -#define LEAF_ERROR ::boost::leaf::next_error_value().propagate(::boost::leaf::meta::e_source_location{__FILE__,__LINE__,__FUNCTION__}),::boost::leaf::error +#define LEAF_ERROR ::boost::leaf::next_error_value().propagate(::boost::leaf::e_source_location{__FILE__,__LINE__,__FUNCTION__}),::boost::leaf::error namespace boost { namespace system { class error_code; } } namespace boost { namespace leaf { - namespace meta + struct e_source_location { - struct e_source_location + char const * const file; + int const line; + char const * const function; + + friend std::ostream & operator<<( std::ostream & os, e_source_location const & x ) { - char const * const file; - int const line; - char const * const function; + return os << "At " << x.file << '(' << x.line << ") in function " << x.function; + } + }; - friend std::ostream & operator<<( std::ostream & os, e_source_location const & x ) - { - return os << "At " << x.file << '(' << x.line << ") in function " << x.function; - } - }; + struct e_unexpected + { + char const * (*first_type)() noexcept; + int count; - struct e_unexpected + friend std::ostream & operator<<( std::ostream & os, e_unexpected const & x ) { - char const * (*first_type)() noexcept; - int count; + assert(x.first_type!=0); + assert(x.count>0); + if( x.count==1 ) + os << "Detected 1 attempt to communicate an unexpected error object of type "; + else + os << "Detected " << x.count << " attempts to communicate unexpected error objects, the first one of type "; + return os << x.first_type(); + } + }; - friend std::ostream & operator<<( std::ostream & os, e_unexpected const & x ) - { - assert(x.first_type!=0); - assert(x.count>0); - return os << "Detected " << x.count << " attempt(s) to communicate unexpected error object(s), the first one is of type " << x.first_type(); - } - }; - } + struct e_unexpected_diagnostic_output + { + std::string value; + + friend std::ostream & operator<<( std::ostream & os, e_unexpected_diagnostic_output const & x ) + { + return os << x.value; + } + }; namespace leaf_detail { @@ -73,8 +85,8 @@ namespace boost { namespace leaf { template <> struct is_error_type: std::true_type { }; template <> struct is_error_type: std::true_type { }; - template <> struct is_error_type: std::true_type { }; - template <> struct is_error_type: std::true_type { }; + template <> struct is_error_type: std::true_type { }; + template <> struct is_error_type: std::true_type { }; //////////////////////////////////////// @@ -218,29 +230,63 @@ namespace boost { namespace leaf { } template - void put_unexpected( leaf_detail::slot & p, error const & e ) noexcept + void put_unexpected( error_info const & ev ) noexcept { - if( p.has_value() ) + if( slot * p = tl_slot_ptr() ) { - auto & v = p.value(); - if( v.e==e ) + if( p->has_value() ) { - ++v.v.count; - return; + auto & p_ev = p->value(); + if( p_ev.e==ev.e ) + { + ++p_ev.v.count; + return; + } } + (void) p->put( error_info{e_unexpected{&type,1},ev.e} ); } - (void) p.put( leaf_detail::error_info{meta::e_unexpected{&type,1},e} ); + } + + template + void put_unexpected_diagnostic_output( error_info const & ev ) noexcept + { + if( slot * p = tl_slot_ptr() ) + { + std::stringstream s; + if( !diagnostic::print(s,ev.v) ) + return; + if( p->has_value() ) + { + auto & p_ev = p->value(); + if( p_ev.e==ev.e ) + { + std::string & value = p_ev.v.value; + value += "\n(unexpected) "; + value += s.str(); + return; + } + } + (void) p->put( error_info{e_unexpected_diagnostic_output{"(unexpected) "+s.str()},ev.e} ); + } + } + + template + void no_expect_slot( error_info const & ev ) noexcept + { + put_unexpected(ev); + put_unexpected_diagnostic_output(ev); } template E * put_slot( E && v, error const & e ) noexcept { - if( leaf_detail::slot * p = leaf_detail::tl_slot_ptr() ) - return &p->put( leaf_detail::error_info{std::forward(v),e} ).v; + if( slot * p = tl_slot_ptr() ) + return &p->put( error_info{std::forward(v),e} ).v; else - if( leaf_detail::slot * p = leaf_detail::tl_slot_ptr() ) - put_unexpected(*p,e); - return 0; + { + no_expect_slot( error_info{std::forward(v),e} ); + return 0; + } } template @@ -261,8 +307,7 @@ namespace boost { namespace leaf { } else if( has_value() ) - if( leaf_detail::slot * p = leaf_detail::tl_slot_ptr() ) - put_unexpected(*p,value().e); + no_expect_slot(value()); tl_slot_ptr() = prev_; } } //leaf_detail diff --git a/test/diagnostic_output_test.cpp b/test/diagnostic_output_test.cpp index ec1734c..89f39c3 100644 --- a/test/diagnostic_output_test.cpp +++ b/test/diagnostic_output_test.cpp @@ -12,6 +12,7 @@ namespace leaf = boost::leaf; +template struct unexpected_test { int value; @@ -73,13 +74,14 @@ int main() { leaf::expect < + leaf::e_source_location, printable_info_printable_payload, printable_info_non_printable_payload, non_printable_info_printable_payload, non_printable_info_non_printable_payload, leaf::e_errno, - leaf::meta::e_source_location, - leaf::meta::e_unexpected + leaf::e_unexpected_diagnostic_output, + leaf::e_unexpected > exp; try { @@ -88,7 +90,8 @@ int main() printable_info_non_printable_payload(), non_printable_info_printable_payload(), non_printable_info_non_printable_payload(), - unexpected_test{42}, + unexpected_test<1>{1}, + unexpected_test<2>{2}, leaf::e_errno{ENOENT} ); } catch( my_error & e ) @@ -97,12 +100,13 @@ int main() current_exception_diagnostic_output(st,exp); std::string s = st.str(); BOOST_TEST(s.find("std::exception::what(): my_error")!=s.npos); - BOOST_TEST(s.find(" = N/A")!=s.npos); - BOOST_TEST(s.find(" = printed printable_payload")!=s.npos); + BOOST_TEST(s.find(": N/A")!=s.npos); + BOOST_TEST(s.find(": printed printable_payload")!=s.npos); BOOST_TEST(s.find("*** printable_info_non_printable_payload ***")!=s.npos); BOOST_TEST(s.find("*** printable_info_printable_payload printed printable_payload ***")!=s.npos); BOOST_TEST(s.find(") in function")!=s.npos); - BOOST_TEST(s.find("Detected 1 attempt(s) to communicate unexpected error object(s), the first one is of type ")!=s.npos); + BOOST_TEST(s.find("Detected 2 attempts to communicate unexpected error objects, the first one of type ")!=s.npos); + BOOST_TEST(s.find("(unexpected) ")!=s.npos); std::cout << s; handle_exception( exp, e, [ ]{ } ); } diff --git a/test/error_test.cpp b/test/error_test.cpp index bf39d94..696a93e 100644 --- a/test/error_test.cpp +++ b/test/error_test.cpp @@ -43,7 +43,7 @@ leaf::error f3() leaf::error f4() { - leaf::expect,info<2>,info<3>,info<4>> exp; + leaf::expect,info<2>,info<3>,info<4>> exp; { leaf::error e = f3(); bool handled = handle_error( exp, e, @@ -58,7 +58,7 @@ leaf::error f4() { ++c1; }, - [&c2]( leaf::meta::e_source_location const & loc, leaf::meta::e_unexpected const & unx, info<1> const & i1, info<2> const & i2, info<4> const & i4 ) + [&c2]( leaf::e_source_location const & loc, leaf::e_unexpected const & unx, info<1> const & i1, info<2> const & i2, info<4> const & i4 ) { BOOST_TEST(loc.line==27); BOOST_TEST(strcmp(loc.file,__FILE__)==0); diff --git a/test/result_test.4.cpp b/test/result_test.4.cpp index af92621..439b9ad 100644 --- a/test/result_test.4.cpp +++ b/test/result_test.4.cpp @@ -15,7 +15,7 @@ template void check( Expect & exp, leaf::bad_result const & e ) { handle_exception( exp, e, - [ ]( leaf::meta::e_source_location const & x ) + [ ]( leaf::e_source_location const & x ) { BOOST_TEST(strstr(x.file,"result.hpp")!=0); BOOST_TEST(x.line>0); @@ -26,7 +26,7 @@ void check( Expect & exp, leaf::bad_result const & e ) int main() { { - leaf::expect exp; + leaf::expect exp; try { leaf::result r((leaf::error())); @@ -39,7 +39,7 @@ int main() } } { - leaf::expect exp; + leaf::expect exp; try { leaf::result const r((leaf::error())); @@ -52,7 +52,7 @@ int main() } } { - leaf::expect exp; + leaf::expect exp; try { leaf::result r((leaf::error())); @@ -65,7 +65,7 @@ int main() } } { - leaf::expect exp; + leaf::expect exp; try { leaf::result const r((leaf::error()));