diff --git a/example/print_file_eh.cpp b/example/print_file_eh.cpp index 75aeb7e..2313c1b 100644 --- a/example/print_file_eh.cpp +++ b/example/print_file_eh.cpp @@ -179,7 +179,7 @@ int main( int argc, char const * argv[ ] ) { //This catch-all case helps diagnose logic errors (presumably, missing catch). std::cerr << "Unknown error, cryptic information follows." << std::endl; - leaf::diagnostic_output_current_exception(std::cerr,exp); + leaf::diagnostic_output_current_exception(std::cerr); return 5; } } diff --git a/example/print_file_result.cpp b/example/print_file_result.cpp index 76832d1..1681305 100644 --- a/example/print_file_result.cpp +++ b/example/print_file_result.cpp @@ -199,7 +199,7 @@ int main( int argc, char const * argv[ ] ) default: { std::cerr << "Unknown error code " << ec << ", cryptic information follows." << std::endl; //<7> - leaf::diagnostic_output(std::cerr,exp,r); + leaf::diagnostic_output(std::cerr,r); return 5; } } diff --git a/example/print_half.cpp b/example/print_half.cpp index 2bc2496..f0b1b22 100644 --- a/example/print_half.cpp +++ b/example/print_half.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -97,13 +98,13 @@ int main( int argc, char const * argv[ ] ) } return 1; }, - [&exp,&r] + [&r] { //This will never execute in this program, but it would detect logic errors where an unknown error reaches main. //In this case, we print diagnostic information. Consider using leaf::unexpected_diagnostic_output in the //definition of exp. std::cerr << "Unknown error, cryptic diagnostic information follows." << std::endl; - leaf::diagnostic_output(std::cerr,exp,r); + leaf::diagnostic_output(std::cerr,r); return 2; } ); } diff --git a/example/return_exception.cpp b/example/return_exception.cpp index ae5d60f..657fa06 100644 --- a/example/return_exception.cpp +++ b/example/return_exception.cpp @@ -100,7 +100,7 @@ int main() //std::exception_ptr, together with any other unknow exception. Presumably this should //never happen, therefore at this point we treat this situation a a logic error: we print //diagnostic information and bail out. - [&exp]( std::exception_ptr const & ep ) + [ ]( std::exception_ptr const & ep ) { assert(ep); try @@ -109,7 +109,7 @@ int main() } catch(...) { - leaf::diagnostic_output_current_exception(std::cerr,exp); + leaf::diagnostic_output_current_exception(std::cerr); } } diff --git a/include/boost/leaf/common.hpp b/include/boost/leaf/common.hpp index 50b4afe..c7c504b 100644 --- a/include/boost/leaf/common.hpp +++ b/include/boost/leaf/common.hpp @@ -9,11 +9,11 @@ #include #include -#include #include #include #ifdef _WIN32 #include +#include #ifdef min #undef min #endif diff --git a/include/boost/leaf/detail/optional.hpp b/include/boost/leaf/detail/optional.hpp index 4508c54..ef7ffe7 100644 --- a/include/boost/leaf/detail/optional.hpp +++ b/include/boost/leaf/detail/optional.hpp @@ -105,32 +105,37 @@ namespace boost { namespace leaf { return value_; } - bool has_value() const noexcept + T const * has_value() const noexcept { - return has_value_; + return has_value_ ? &value_ : 0; + } + + T * has_value() noexcept + { + return has_value_ ? &value_ : 0; } T const & value() const & noexcept { - assert(has_value()); + assert(has_value()!=0); return value_; } T & value() & noexcept { - assert(has_value()); + assert(has_value()!=0); return value_; } T const && value() const && noexcept { - assert(has_value()); + assert(has_value()!=0); return value_; } T value() && noexcept { - assert(has_value()); + assert(has_value()!=0); T tmp(std::move(value_)); reset(); return tmp; diff --git a/include/boost/leaf/diagnostic_output.hpp b/include/boost/leaf/diagnostic_output.hpp new file mode 100644 index 0000000..eb3b75b --- /dev/null +++ b/include/boost/leaf/diagnostic_output.hpp @@ -0,0 +1,53 @@ +#ifndef BOOST_LEAF_7062AB340F9411E9A7CFDBC88C7F4AFC +#define BOOST_LEAF_7062AB340F9411E9A7CFDBC88C7F4AFC + +//Copyright (c) 2018 Emil Dotchevski +//Copyright (c) 2018 Second Spectrum, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +namespace boost { namespace leaf { + + namespace leaf_detail + { + inline void slot_base::diagnostic_output( std::ostream & os, error const * e ) + { + for( slot_base const * p = first(); p; p=p->next_ ) + if( p->slot_diagnostic_output(os,e) ) + os << std::endl; + } + } + + inline void diagnostic_output( std::ostream & os, error const & e ) + { + os << "leaf::error serial number: " << e << std::endl; + leaf_detail::slot_base::diagnostic_output(os,&e); + } + + inline void diagnostic_output( std::ostream & os ) + { + leaf_detail::slot_base::diagnostic_output(os,0); + } + + template + class result; + + template + void diagnostic_output( std::ostream & os, result const & r ) + { + assert(!r); + if( r.which_==leaf_detail::result_variant::err ) + return diagnostic_output(os,r.err_); + else + { + assert(r.which_==leaf_detail::result_variant::cap); + return diagnostic_output(os,r.cap_); + } + } + +} } + +#endif diff --git a/include/boost/leaf/diagnostic_output_current_exception.hpp b/include/boost/leaf/diagnostic_output_current_exception.hpp index a863c7e..d2097cd 100644 --- a/include/boost/leaf/diagnostic_output_current_exception.hpp +++ b/include/boost/leaf/diagnostic_output_current_exception.hpp @@ -8,12 +8,13 @@ //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include #include namespace boost { namespace leaf { template - void diagnostic_output_current_exception( std::ostream & os, expect const & exp ) + void diagnostic_output_current_exception( std::ostream & os ) { os << "Current Exception Diagnostic Information:" << std::endl; @@ -42,11 +43,11 @@ namespace boost { namespace leaf { } catch( error const & e ) { - diagnostic_output(os,exp,e); + diagnostic_output(os,e); } catch( ... ) { - diagnostic_output(os,exp); + diagnostic_output(os); } } diff --git a/include/boost/leaf/error.hpp b/include/boost/leaf/error.hpp index 406e102..7a5cb66 100644 --- a/include/boost/leaf/error.hpp +++ b/include/boost/leaf/error.hpp @@ -55,11 +55,25 @@ namespace boost { namespace leaf { { std::string value; std::set already; - friend std::ostream & operator<<( std::ostream & os, e_unexpected_diagnostic_output const & x ) noexcept { return os; } }; namespace leaf_detail { + template <> + struct diagnostic + { + static bool print( std::ostream & os, e_unexpected_diagnostic_output const & x ) noexcept + { + if( x.value.empty() ) + return false; + else + { + os << x.value; + return true; + } + } + }; + template struct has_data_member_value { @@ -216,8 +230,44 @@ namespace boost { namespace leaf { return c; } + class slot_base + { + slot_base( slot_base const & ) = delete; + slot_base & operator=( slot_base const & ) = delete; + + virtual bool slot_diagnostic_output( std::ostream &, error const * e ) const = 0; + + public: + + static void diagnostic_output( std::ostream & os, error const * e ); + + protected: + + static slot_base const * & first() noexcept + { + static thread_local slot_base const * p = 0; + return p; + } + + slot_base const * const next_; + + slot_base() noexcept: + next_(first()) + { + first() = this; + } + + ~slot_base() noexcept + { + slot_base const * & p = first(); + assert(p==this); + p = next_; + } + }; + template class slot: + slot_base, optional> { slot( slot const & ) = delete; @@ -225,10 +275,16 @@ namespace boost { namespace leaf { typedef optional> base; slot * prev_; static_assert(is_error_type::value,"Not an error type"); + + bool slot_diagnostic_output( std::ostream & os, error const * e ) const; + protected: + slot() noexcept; ~slot() noexcept; + public: + using base::put; using base::has_value; using base::value; @@ -336,6 +392,27 @@ namespace boost { namespace leaf { tl_slot_ptr() = prev_; } + template + bool slot::slot_diagnostic_output( std::ostream & os, error const * e ) const + { + if( tl_slot_ptr()==this ) + if( error_info const * ev = has_value() ) + if( e ) + { + if( ev->e==*e ) + return diagnosticv)>::print(os,ev->v); + } + else + { + if( diagnosticv)>::print(os,ev->v) ) + { + os << " {" << ev->e << '}'; + return true; + } + } + return false; + } + template error make_error( char const * file, int line, char const * function, E && ... e ) { @@ -346,14 +423,12 @@ namespace boost { namespace leaf { return error( std::move(sl), std::forward(e)... ); } - inline void diagnostic_output_prefix( std::ostream & os, leaf::error const * e ) + enum class result_variant { - if( e ) - os << "leaf::error serial number: " << *e << std::endl; - if( leaf_detail::slot const * unx = leaf_detail::tl_slot_ptr() ) - if( unx->has_value() ) - os << unx->value().v.value << std::endl; - } + value, + err, + cap + }; } //leaf_detail template diff --git a/include/boost/leaf/error_capture.hpp b/include/boost/leaf/error_capture.hpp index 2483f5b..d652a85 100644 --- a/include/boost/leaf/error_capture.hpp +++ b/include/boost/leaf/error_capture.hpp @@ -163,7 +163,6 @@ namespace boost { namespace leaf { void diagnostic_output_( std::ostream & os ) const { - leaf_detail::diagnostic_output_prefix(os,0); leaf_detail::tuple_for_each_capture::print(os,s_); } diff --git a/include/boost/leaf/expect.hpp b/include/boost/leaf/expect.hpp index 9b2b7fa..f5f049f 100644 --- a/include/boost/leaf/expect.hpp +++ b/include/boost/leaf/expect.hpp @@ -98,50 +98,6 @@ namespace boost { namespace leaf { //////////////////////////////////////// - template - struct tuple_for_each_expect - { - static void print( std::ostream & os, Tuple const & tup ) - { - tuple_for_each_expect::print(os,tup); - auto & opt = std::get(tup); - if( opt.has_value() ) - { - auto & x = opt.value(); - if( diagnostic::print(os,x.v) ) - os << " {" << x.e << '}' << std::endl; - } - } - - static void print( std::ostream & os, Tuple const & tup, error const & e ) - { - tuple_for_each_expect::print(os,tup,e); - auto & opt = std::get(tup); - if( opt.has_value() ) - { - auto & x = opt.value(); - if( x.e==e && diagnostic::print(os,x.v) ) - os << std::endl; - } - } - - static void clear( Tuple & tup ) noexcept - { - tuple_for_each_expect::clear(tup); - std::get(tup).reset(); - } - }; - - template - struct tuple_for_each_expect<0, Tuple> - { - static void print( std::ostream &, Tuple const & ) noexcept { } - static void print( std::ostream &, Tuple const &, error const & ) noexcept { } - static void clear( Tuple & ) noexcept { } - }; - - //////////////////////////////////////// - template optional convert_optional( expect_slot && x, error const & e ) noexcept { @@ -167,11 +123,6 @@ namespace boost { namespace leaf { template P const * peek( expect const &, error const & ) noexcept; - template - void diagnostic_output( std::ostream &, expect const & ); - - template - void diagnostic_output( std::ostream &, expect const &, error const & ); template typename leaf_detail::dependent_type>::error_capture capture( expect &, error const & ); @@ -187,12 +138,6 @@ namespace boost { namespace leaf { template friend P const * leaf::peek( expect const &, error const & ) noexcept; - template - friend void leaf::diagnostic_output( std::ostream &, expect const & ); - - template - friend void leaf::diagnostic_output( std::ostream &, expect const &, error const & ); - template friend typename leaf_detail::dependent_type>::error_capture leaf::capture( expect &, error const & ); @@ -255,20 +200,6 @@ namespace boost { namespace leaf { return 0; } - template - void diagnostic_output( std::ostream & os, expect const & exp ) - { - leaf_detail::diagnostic_output_prefix(os,0); - leaf_detail::tuple_for_each_expect::print(os,exp.s_); - } - - template - void diagnostic_output( std::ostream & os, expect const & exp, error const & e ) - { - leaf_detail::diagnostic_output_prefix(os,&e); - leaf_detail::tuple_for_each_expect::print(os,exp.s_,e); - } - template typename leaf_detail::dependent_type>::error_capture capture( expect & exp, error const & e ) { diff --git a/include/boost/leaf/result.hpp b/include/boost/leaf/result.hpp index 3120714..a84af36 100644 --- a/include/boost/leaf/result.hpp +++ b/include/boost/leaf/result.hpp @@ -38,24 +38,14 @@ namespace boost { namespace leaf { template P const * peek( expect const &, result const & ) noexcept; - template - void diagnostic_output( std::ostream &, expect const &, result const & ); + template + void diagnostic_output( std::ostream &, result const & ); template result capture( expect &, result const & ); //////////////////////////////////////// - namespace leaf_detail - { - enum class result_variant - { - value, - err, - cap - }; - } - template class result { @@ -65,8 +55,8 @@ namespace boost { namespace leaf { template friend P const * leaf::peek( expect const &, result const & ) noexcept; - template - friend void leaf::diagnostic_output( std::ostream &, expect const &, result const & ); + template + friend void leaf::diagnostic_output( std::ostream &, result const & ); template friend result leaf::capture( expect &, result const & ); @@ -254,12 +244,12 @@ namespace boost { namespace leaf { case leaf_detail::result_variant::value: return leaf::error(std::forward(e)...); case leaf_detail::result_variant::cap: - { - error_capture cap = cap_; - destroy(); - (void) new(&err_) leaf::error(cap.unload()); - which_ = leaf_detail::result_variant::err; - } + { + error_capture cap = cap_; + destroy(); + (void) new(&err_) leaf::error(cap.unload()); + which_ = leaf_detail::result_variant::err; + } default: assert(which_==leaf_detail::result_variant::err); return err_.propagate(std::forward(e)...); @@ -279,8 +269,8 @@ namespace boost { namespace leaf { template friend P const * leaf::peek( expect const &, result const & ) noexcept; - template - friend void leaf::diagnostic_output( std::ostream &, expect const &, result const & ); + template + friend void leaf::diagnostic_output( std::ostream &, result const & ); template friend result leaf::capture( expect &, result const & ); @@ -350,19 +340,6 @@ namespace boost { namespace leaf { } } - template - void diagnostic_output( std::ostream & os, expect const & exp, result const & r ) - { - assert(!r); - if( r.which_==leaf_detail::result_variant::err ) - return diagnostic_output(os,exp,r.err_); - else - { - assert(r.which_==leaf_detail::result_variant::cap); - return diagnostic_output(os,r.cap_); - } - } - template result capture( expect & exp, result const & r ) { diff --git a/test/diagnostic_output_test.cpp b/test/diagnostic_output_test.cpp index 866b347..e697d74 100644 --- a/test/diagnostic_output_test.cpp +++ b/test/diagnostic_output_test.cpp @@ -99,7 +99,7 @@ int main() catch( my_error & e ) { std::ostringstream st; - diagnostic_output_current_exception(st,exp); + leaf::diagnostic_output_current_exception(st); std::string s = st.str(); BOOST_TEST(s.find("std::exception::what(): my_error")!=s.npos); BOOST_TEST(s.find(": N/A")!=s.npos); @@ -108,7 +108,7 @@ int main() 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 2 attempts to communicate unexpected error objects, the first one of type ")!=s.npos); - BOOST_TEST(s.find("unexpected_test")!=s.npos); + BOOST_TEST(s.find("unexpected_test<2>")!=s.npos); std::cout << s; handle_exception( exp, e, [ ]{ } ); }