diff --git a/.vscode/launch.json b/.vscode/launch.json index 5cb39f5..013fc84 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,7 +8,7 @@ "name": "(lldb) Launch", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/bld/debug/capture_eh", + "program": "${workspaceFolder}/bld/debug/exception_capture_test", "args": [ "test/Jafile.v2" ], "cwd": "${workspaceFolder}", "stopAtEntry": false, diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2b3a6a0..043133e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -16,6 +16,97 @@ "type": "shell", "command": "cd ${workspaceRoot}/bld/debug && meson test", "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "basic_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test basic_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "diagnostic_print_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test diagnostic_print_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "error_capture_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test error_capture_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "error_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test error_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "exception_capture_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test exception_capture_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "exception_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test exception_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "multiple_errors_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test multiple_errors_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "optional_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test optional_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "preload_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test preload_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "print_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test print_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "result_capture_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test result_capture_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "result_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test result_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } + }, + { + "group": { "kind": "test", "isDefault": false }, + "label": "result_void_capture_test", + "type": "shell", + "command": "cd ${workspaceRoot}/bld/debug && meson test result_void_capture_test", + "problemMatcher": { "base": "$gcc", "fileLocation": ["relative","${workspaceRoot}/bld/debug"] } } ] } \ No newline at end of file diff --git a/example/capture_eh.cpp b/example/capture_eh.cpp index 8c23845..d57edda 100644 --- a/example/capture_eh.cpp +++ b/example/capture_eh.cpp @@ -90,7 +90,7 @@ int main() catch( failure const & e ) { //Failure! Handle error, print failure info. - handle_error( exp, e, + handle_exception( exp, e, leaf::match( [ ] ( std::string const & v1, int v2, std::thread::id tid ) { std::cerr << "Error in thread " << tid << "! failure_info1: " << v1 << ", failure_info2: " << v2 << std::endl; diff --git a/example/capture_result.cpp b/example/capture_result.cpp index 6fcda51..151a710 100644 --- a/example/capture_result.cpp +++ b/example/capture_result.cpp @@ -81,11 +81,12 @@ int main() else { //Failure! Handle error, print failure info. - handle_error( exp, r, + bool matched = handle_error( exp, r, leaf::match( [ ] ( std::string const & v1, int v2, std::thread::id tid ) { std::cerr << "Error in thread " << tid << "! failure_info1: " << v1 << ", failure_info2: " << v2 << std::endl; } ) ); + assert(matched); } } } diff --git a/example/print_file_eh.cpp b/example/print_file_eh.cpp index 1d551d3..10cc71c 100644 --- a/example/print_file_eh.cpp +++ b/example/print_file_eh.cpp @@ -17,8 +17,8 @@ namespace leaf = boost::leaf; //We could define our own error info types, but for this example the ones //defined in are a perfect match. -using leaf::ei_file_name; -using leaf::ei_errno; +using leaf::e_file_name; +using leaf::e_errno; //Exception type hierarchy. struct print_file_error : virtual std::exception { }; @@ -29,19 +29,19 @@ struct file_error : virtual io_error { }; struct file_open_error : virtual file_error { }; struct file_size_error : virtual file_error { }; struct file_read_error : virtual file_error { }; -struct file_eof_error : virtual file_error { }; +struct eof_error : virtual file_error { }; std::shared_ptr file_open( char const * file_name ) { if( FILE * f = fopen(file_name,"rb") ) return std::shared_ptr(f,&fclose); else - leaf::throw_exception( file_open_error(), ei_file_name{file_name}, ei_errno{errno} ); + leaf::throw_exception( file_open_error(), e_file_name{file_name}, e_errno{errno} ); } int file_size( FILE & f ) { - auto put = leaf::preload(&leaf::get_errno); + auto propagate = leaf::defer(&leaf::get_errno); if( fseek(&f,0,SEEK_END) ) throw file_size_error(); @@ -61,17 +61,18 @@ void file_read( FILE & f, void * buf, int size ) int n = fread(buf,1,size,&f); if( ferror(&f) ) - leaf::throw_exception( file_read_error(), ei_errno{errno} ); + leaf::throw_exception( file_read_error(), e_errno{errno} ); if( n!=size ) - throw file_eof_error(); + throw eof_error(); } void print_file( char const * file_name ) { - auto put = leaf::preload( ei_file_name{file_name} ); - std::shared_ptr f = file_open( file_name ); + + leaf::preload( e_file_name{file_name} ); + std::string buffer( 1+file_size(*f), '\0' ); file_read(*f,&buffer[0],buffer.size()-1); @@ -90,8 +91,8 @@ int main( int argc, char const * argv[ ] ) { std::cout.exceptions ( std::ostream::failbit | std::ostream::badbit ); - //We expect ei_file_name and ei_errno info to arrive with exceptions handled in this function. - leaf::expect exp; + //We expect e_file_name and e_errno info to arrive with exceptions handled in this function. + leaf::expect exp; try { @@ -105,8 +106,11 @@ int main( int argc, char const * argv[ ] ) catch( file_open_error const & e ) { //handle_error is given a list of match objects (in this case only one), which it attempts to match (in order) to - //available exception info (if none can be matched, it throws leaf::mismatch_error). - handle_error( exp, e, leaf::match( [ ] ( std::string const & fn, int errn ) + //available error info (if none can be matched, it rethrows the current exception, which in this program would + //be a logic error, since it doesn't catch that exception. When a match is found, the corresponding lambda + //is invoked. + handle_exception( exp, e, + leaf::match( [ ] ( std::string const & fn, int errn ) { if( errn==ENOENT ) std::cerr << "File not found: " << fn << std::endl; @@ -117,23 +121,23 @@ int main( int argc, char const * argv[ ] ) } catch( io_error const & e ) { - //handle_error is given a list of match objects, which it attempts to match (in order) to available exception info. - //In this case it will first check if both ei_file_name and ei_errno are avialable; if not, it will next check - //if just ei_errno is available; and if not, the last match will match even if no exception info is available, - //to print a generic error message. - handle_error( exp, e, - leaf::match( [ ] ( std::string const & fn, int errn ) - { - std::cerr << "Failed to access " << fn << ", errno=" << errn << std::endl; - } ), - leaf::match( [ ] ( int errn ) - { - std::cerr << "I/O error, errno=" << errn << std::endl; - } ), + //handle_error is given a list of match objects, which it attempts to match (in order) to available error info. + //In this case it will first check if both e_file_name and e_errno are avialable; if not, it will next check + //if just e_errno is available; and if not, the last match will match even if no error info is available, to + //print a generic error message. + handle_exception( exp, e, + leaf::match( [ ] ( std::string const & fn, int errn ) + { + std::cerr << "Failed to access " << fn << ", errno=" << errn << std::endl; + } ), + leaf::match( [ ] ( int errn ) + { + std::cerr << "I/O error, errno=" << errn << std::endl; + } ), leaf::match<>( [ ] - { - std::cerr << "I/O error" << std::endl; - } ) ); + { + std::cerr << "I/O error" << std::endl; + } ) ); return 3; } catch(...) @@ -144,4 +148,4 @@ int main( int argc, char const * argv[ ] ) return 4; } return 0; - } +} diff --git a/example/print_file_result.cpp b/example/print_file_result.cpp index 2febbd2..40e7efe 100644 --- a/example/print_file_result.cpp +++ b/example/print_file_result.cpp @@ -17,42 +17,42 @@ namespace leaf = boost::leaf; //We could define our own error info types, but for this example the ones //defined in are a perfect match. -using leaf::ei_file_name; -using leaf::ei_errno; +using leaf::e_file_name; +using leaf::e_errno; //Errors -enum print_file_error_enum +enum class print_file_error { - file_open_error, - file_size_error, - file_read_error, - file_eof_error, - cout_error + file_open, + file_size, + file_read, + eof, + cout_write }; -struct ei_error_code { print_file_error_enum value; }; +struct e_print_file_error { print_file_error value; }; leaf::result> file_open( char const * file_name ) { if( FILE * f = fopen(file_name,"rb") ) return std::shared_ptr(f,&fclose); else - return leaf::error( ei_error_code{file_open_error}, ei_file_name{file_name}, ei_errno{errno} ); + return leaf::error( e_print_file_error{print_file_error::file_open}, e_file_name{file_name}, e_errno{errno} ); } leaf::result file_size( FILE & f ) { - auto put = leaf::preload(&leaf::get_errno); + auto propagate = leaf::defer(&leaf::get_errno); if( fseek(&f,0,SEEK_END) ) - return leaf::error( ei_error_code{file_size_error} ); + return leaf::error( e_print_file_error{print_file_error::file_size} ); int s = ftell(&f); if( s==-1L ) - return leaf::error( ei_error_code{file_size_error} ); + return leaf::error( e_print_file_error{print_file_error::file_size} ); if( fseek(&f,0,SEEK_SET) ) - return leaf::error( ei_error_code{file_size_error} ); + return leaf::error( e_print_file_error{print_file_error::file_size} ); return s; } @@ -61,31 +61,31 @@ leaf::result file_read( FILE & f, void * buf, int size ) { int n = fread(buf,1,size,&f); if( ferror(&f) ) - return leaf::error( ei_error_code{file_read_error}, ei_errno{errno} ); + return leaf::error( e_print_file_error{print_file_error::file_read}, e_errno{errno} ); if( n!=size ) - return leaf::error( ei_error_code{file_eof_error} ); + return leaf::error( e_print_file_error{print_file_error::eof} ); return { }; } leaf::result print_file( char const * file_name ) { - LEAF_CHECK(f,file_open(file_name)); + LEAF_AUTO(f,file_open(file_name)); - auto put = leaf::preload( ei_file_name{file_name} ); + leaf::preload( e_file_name{file_name} ); + + LEAF_AUTO(s,file_size(*f)); - LEAF_CHECK(s,file_size(*f)); std::string buffer( 1+s, '\0' ); + LEAF_CHECK(file_read(*f,&buffer[0],buffer.size()-1)); - LEAF_CHECK_(file_read(*f,&buffer[0],buffer.size()-1)); std::cout << buffer; - std::cout.flush(); if( std::cout.fail() ) - return leaf::error( ei_error_code{cout_error} ); - else - return { }; + return leaf::error( e_print_file_error{print_file_error::cout_write} ); + + return { }; } char const * parse_command_line( int argc, char const * argv[ ] ) @@ -105,50 +105,65 @@ int main( int argc, char const * argv[ ] ) return 1; } - //We expect ei_error_code, ei_file_name and ei_errno error info to arrive with exceptions handled in this function. - leaf::expect exp; + //We expect e_print_file_error, e_file_name and e_errno error info to arrive with errors handled in this function. + leaf::expect exp; + if( auto r = print_file(fn) ) - return 0; + { + return 0; //Success, we're done! + } else - switch( auto ec=*leaf::peek(exp,r) ) + { + switch( auto ec = *leaf::peek(exp,r) ) //Switch based on the reported e_print_file_error. { - case file_open_error: - //handle_error is given a list of match objects (in this case only one), which it attempts to match (in order) to - //available error info (if none can be matched, it throws leaf::mismatch_error, which in this program would - //be a logic error, since it's not supposed to throw exceptions). - handle_error( exp, r, leaf::match( [ ] ( std::string const & fn, int errn ) - { - if( errn==ENOENT ) - std::cerr << "File not found: " << fn << std::endl; - else - std::cerr << "Failed to open " << fn << ", errno=" << errn << std::endl; - } ) ); - return 2; - case file_size_error: - case file_read_error: - case file_eof_error: - //handle_error is given a list of match objects, which it attempts to match (in order) to available error info. - //In this case it will first check if both ei_file_name and ei_errno are avialable; if not, it will next check - //if just ei_errno is available; and if not, the last match will match even if no error info is available, - //to print a generic error message. - handle_error( exp, r, - leaf::match( [ ] ( std::string const & fn, int errn ) - { - std::cerr << "Failed to access " << fn << ", errno=" << errn << std::endl; - } ), - leaf::match( [ ] ( int errn ) - { - std::cerr << "I/O error, errno=" << errn << std::endl; - } ), - leaf::match<>( [ ] - { - std::cerr << "I/O error" << std::endl; - } ) ); - return 3; - default: - //This catch-all is designed to help diagnose logic errors (missing case labels in the switch statement). - std::cerr << "Unknown error code " << ec << ", cryptic information follows." << std::endl; - diagnostic_print(std::cerr,exp,r); - return 4; + case print_file_error::file_open: + { + //handle_error is given a list of match objects (in this case only one), which it attempts to match (in order) to + //available error info (if none can be matched, it returns false). When a match is found, the corresponding + //lambda is invoked. + bool matched = handle_error( exp, r, + leaf::match( [ ] ( std::string const & fn, int errn ) + { + if( errn==ENOENT ) + std::cerr << "File not found: " << fn << std::endl; + else + std::cerr << "Failed to open " << fn << ", errno=" << errn << std::endl; + } ) ); + assert(matched); + return 2; + } + + case print_file_error::cout_write: + case print_file_error::file_size: + case print_file_error::file_read: + case print_file_error::eof: + { + //handle_error is given a list of match objects, which it attempts to match (in order) to available error info. + //In this case it will first check if both e_file_name and e_errno are avialable; if not, it will next check + //if just e_errno is available; and if not, the last match will match even if no error info is available, + //to print a generic error message. + bool matched = handle_error( exp, r, + leaf::match( [ ] ( std::string const & fn, int errn ) + { + std::cerr << "Failed to access " << fn << ", errno=" << errn << std::endl; + } ), + leaf::match( [ ] ( int errn ) + { + std::cerr << "I/O error, errno=" << errn << std::endl; + } ), + leaf::match<>( [ ] + { + std::cerr << "I/O error" << std::endl; + } ) ); + assert(matched); + return 3; + } + + default: + //This catch-all case is designed to help diagnose logic errors (missing case labels in the switch statement). + std::cerr << "Unknown error code " << int(ec) << ", cryptic information follows." << std::endl; + diagnostic_print(std::cerr,exp,r); + return 4; } + } } diff --git a/include/boost/leaf/all.hpp b/include/boost/leaf/all.hpp index d4325f9..ef68861 100644 --- a/include/boost/leaf/all.hpp +++ b/include/boost/leaf/all.hpp @@ -10,6 +10,5 @@ #include #include #include -#include #include #include diff --git a/include/boost/leaf/common.hpp b/include/boost/leaf/common.hpp index 5f3386a..409a2e2 100644 --- a/include/boost/leaf/common.hpp +++ b/include/boost/leaf/common.hpp @@ -13,7 +13,7 @@ #include #include -#define LEAF_SOURCE_LOCATION ::boost::leaf::ei_source_location{::boost::leaf::ei_source_location::loc(__FILE__,__LINE__,__FUNCTION__)} +#define LEAF_SOURCE_LOCATION ::boost::leaf::e_source_location{::boost::leaf::e_source_location::loc(__FILE__,__LINE__,__FUNCTION__)} namespace boost @@ -22,7 +22,7 @@ boost leaf { struct - ei_source_location + e_source_location { struct loc @@ -43,35 +43,35 @@ boost loc value; friend std::ostream & - operator<<( std::ostream & os, ei_source_location const & x ) + operator<<( std::ostream & os, e_source_location const & x ) { return os << "At " << x.value.file << '(' << x.value.line << ") in function " << x.value.function << std::endl; } }; //////////////////////////////////////// - struct ei_api_function { char const * value; }; - struct ei_file_name { std::string value; }; + struct e_api_function { char const * value; }; + struct e_file_name { std::string value; }; //////////////////////////////////////// struct - ei_errno + e_errno { int value; friend inline std::ostream & - operator<<( std::ostream & os, ei_errno const & err ) + operator<<( std::ostream & os, e_errno const & err ) { using namespace std; - os << type() << " = " << err.value << ", \"" << std::strerror(err.value) << '"'; + os << type() << " = " << err.value << ", \"" << std::strerror(err.value) << '"'; return os; } }; inline - ei_errno + e_errno get_errno() noexcept { using namespace std; - return ei_errno{errno}; + return e_errno{errno}; } } } diff --git a/include/boost/leaf/detail/optional.hpp b/include/boost/leaf/detail/optional.hpp index b09018a..09486b2 100644 --- a/include/boost/leaf/detail/optional.hpp +++ b/include/boost/leaf/detail/optional.hpp @@ -65,7 +65,7 @@ boost { reset(); if( x.has_value() ) - put(x.extract_value()); + put(std::move(x).value()); return *this; } ~optional() noexcept @@ -103,19 +103,25 @@ boost return has_value_; } T const & - value() const noexcept + value() const & noexcept { assert(has_value()); return value_; } T & - value() noexcept + value() & noexcept + { + assert(has_value()); + return value_; + } + T const && + value() const && noexcept { assert(has_value()); return value_; } T - extract_value() noexcept + value() && noexcept { assert(has_value()); T tmp(std::move(value_)); diff --git a/include/boost/leaf/error.hpp b/include/boost/leaf/error.hpp index 6fac0d2..553d524 100644 --- a/include/boost/leaf/error.hpp +++ b/include/boost/leaf/error.hpp @@ -11,7 +11,6 @@ #include #include #include -#include #include namespace @@ -20,55 +19,79 @@ boost namespace leaf { - class error; - namespace - leaf_detail - { - template - T * put1( T && v, error const & e ) noexcept; - error const & set_current_error( error const & ) noexcept; - struct current_error_state; - } - //////////////////////////////////////// class error { - friend struct leaf_detail::current_error_state; - unsigned id_; - - struct default_ { }; explicit - error( default_ ) noexcept: - id_(-1) + error( unsigned id ) noexcept: + id_(id) { } - static - unsigned - new_id() noexcept + class + id_factory { - static std::atomic x; - return ++x; - } + id_factory( id_factory const & ) = delete; + id_factory & operator=( id_factory const & ) = delete; + static + unsigned + new_error_id() noexcept + { + static std::atomic c; + return ++c; + } + bool next_id_valid_; + unsigned next_id_; + id_factory() noexcept: + next_id_valid_(false) + { + } + public: + static + id_factory & + tl_instance() noexcept + { + static thread_local id_factory s; + return s; + } + unsigned + peek() noexcept + { + if( !next_id_valid_ ) + { + next_id_ = new_error_id(); + next_id_valid_ = true; + } + return next_id_; + } + unsigned + get() noexcept + { + if( next_id_valid_ ) + { + next_id_valid_ = false; + return next_id_; + } + else + return new_error_id(); + } + void + reset_peek() noexcept + { + next_id_valid_ = false; + } + }; public: error() noexcept: - id_(new_id()) + id_(id_factory::tl_instance().get()) { - (void) leaf_detail::set_current_error(*this); } template explicit error( T && ... v ) noexcept: - id_(new_id()) + id_(id_factory::tl_instance().get()) { - (void) leaf_detail::set_current_error(propagate(std::forward(v)...)); - } - template - error - propagate( T && ... v ) const noexcept - { - { using _ = void const * [ ]; (void) _ { 0, leaf_detail::put1(std::forward(v),*this)... }; } - return *this; + propagate(std::forward(v)...); } friend bool @@ -93,70 +116,23 @@ boost os << buf; return os; } + static + error + peek_next_error() noexcept + { + return error(id_factory::tl_instance().peek()); + } + static + void + clear_next_error() noexcept + { + id_factory::tl_instance().reset_peek(); + } + template + error propagate( T && ... ) const noexcept; }; //////////////////////////////////////// namespace - leaf_detail - { - struct - current_error_state - { - error e; - error const * ep; - current_error_state() noexcept: - e(error::default_()), - ep(0) - { - } - static - current_error_state & - tl_instance() noexcept - { - static thread_local current_error_state s; - return s; - } - }; - inline - error const & - set_current_error( error const & e ) noexcept - { - auto & x = current_error_state::tl_instance(); - assert(!x.ep); - return *(x.ep = &(x.e = e)); - } - inline - void - clear_current_error() noexcept - { - current_error_state::tl_instance().ep = 0; - } - inline - void - clear_current_error( error const & e ) noexcept - { - auto & x = current_error_state::tl_instance(); - if( x.ep && *x.ep==e ) - x.ep = 0; - } - } - inline - error const * - current_error() noexcept - { - auto & x = leaf_detail::current_error_state::tl_instance(); - if( error const * e = x.ep ) - return e; - else if( std::uncaught_exception() ) - { - error new_error; - assert(*x.ep==new_error); - return x.ep; - } - else - return 0; - } - //////////////////////////////////////// - namespace leaf_detail { template @@ -200,14 +176,12 @@ boost ~slot() noexcept { if( prev_ && this->has_value() ) - if( auto ce = current_error() ) - if( *ce==this->value().e ) - (void) prev_->put(this->extract_value()); + (void) prev_->put(std::move(*this).value()); tl_slot_ptr() = prev_; } template T * - put1( T && v, error const & e ) noexcept + put_slot( T && 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; @@ -215,15 +189,47 @@ boost return 0; } } - //////////////////////////////////////// - template + template error - propagate( E && ... e ) noexcept + error:: + propagate( T && ... v ) const noexcept { - if( error const * ce = current_error() ) - return ce->propagate(std::forward(e)...); - else - return error(std::forward(e)...); + { using _ = void const * [ ]; (void) _ { 0, leaf_detail::put_slot(std::forward(v),*this)... }; } + return *this; + } + //////////////////////////////////////// + namespace + leaf_detail + { + template + class + deferred + { + error const e_; + F f_; + public: + deferred( error const & e, F && f ) noexcept: + e_(e), + f_(std::forward(f)) + { + } + ~deferred() noexcept + { + (void) e_.propagate(f_()); + } + }; + } + template + leaf_detail::deferred + defer( F && f ) noexcept + { + return leaf_detail::deferred(error::peek_next_error(),std::forward(f)); + } + template + void + preload( T && ... a ) + { + error::peek_next_error().propagate(std::forward(a)...); } //////////////////////////////////////// namespace diff --git a/include/boost/leaf/error_capture.hpp b/include/boost/leaf/error_capture.hpp index 01fc526..4e79858 100644 --- a/include/boost/leaf/error_capture.hpp +++ b/include/boost/leaf/error_capture.hpp @@ -96,19 +96,19 @@ boost { static void - propagate( error const & e, Tuple & tup ) noexcept + propagate( error const & e, Tuple && tup ) noexcept { - tuple_propagate::propagate(e,tup); - auto & opt = std::get(tup); + tuple_propagate::propagate(e,std::move(tup)); + auto && opt = std::get(std::move(tup)); if( opt.has_value() ) - e.propagate(opt.extract_value()); + e.propagate(std::move(opt).value()); } }; template struct tuple_propagate<0,Tuple> { - static void propagate( error const &, Tuple & ) noexcept { } + static void propagate( error const &, Tuple && ) noexcept { } }; } //////////////////////////////////////// @@ -183,7 +183,7 @@ boost void propagate( error const & e ) noexcept { - leaf_detail::tuple_propagate::propagate(e,s_); + leaf_detail::tuple_propagate::propagate(e,std::move(s_)); } }; void @@ -197,7 +197,7 @@ boost } template int - unwrap( leaf_detail::match_fn const & m, bool & matched ) const noexcept + unwrap( leaf_detail::match_fn const & m, bool & matched ) const { if( !matched && (matched=leaf_detail::all_available::check(*this)) ) (void) m.f( *peek(*this)... ); @@ -211,8 +211,14 @@ boost matched = leaf_detail::all_available::check(*this); return 42; } - error e_; dynamic_store * s_; + error e_; + protected: + void + set_error( error const & e ) + { + e_ = e; + } public: error_capture() noexcept: s_(0) @@ -220,8 +226,8 @@ boost } template error_capture( error const & e, std::tuple...> && s ) noexcept: - e_(e), - s_(new dynamic_store_impl(std::move(s))) + s_(new dynamic_store_impl(std::move(s))), + e_(e) { s_->addref(); } @@ -230,32 +236,32 @@ boost free(); } error_capture( error_capture const & x ) noexcept: - e_(x.e_), - s_(x.s_) + s_(x.s_), + e_(x.e_) { if( s_ ) s_->addref(); } error_capture( error_capture && x ) noexcept: - e_(std::move(x.e_)), - s_(x.s_) + s_(x.s_), + e_(std::move(x.e_)) { x.s_ = 0; } error_capture & operator=( error_capture const & x ) noexcept { - e_ = x.e_; s_ = x.s_; s_->addref(); + e_ = x.e_; return *this; } error_capture & operator=( error_capture && x ) noexcept { - e_ = x.e_; s_ = x.s_; x.s_ = 0; + e_ = x.e_; return *this; } explicit @@ -275,17 +281,17 @@ boost } template friend - void - handle_error( error_capture & e, M && ... m ) + bool + handle_error( error_capture const & e, M && ... m ) noexcept { if( e ) { bool matched = false; { using _ = int[ ]; (void) _ { 42, e.unwrap(m,matched)... }; } - if( !matched ) - throw_exception(mismatch_error(),e.e_); - e.free(); + if( matched ) + return true; } + return false; } friend void diff --git a/include/boost/leaf/exception.hpp b/include/boost/leaf/exception.hpp index faf1872..39f292c 100644 --- a/include/boost/leaf/exception.hpp +++ b/include/boost/leaf/exception.hpp @@ -23,22 +23,23 @@ boost if( auto err = dynamic_cast(&e) ) return peek

(exp,*err); else - { - assert(current_error()!=0); - return peek

(exp,*current_error()); - } + return peek

(exp,error::peek_next_error()); } template void - handle_error( expect const & exp, std::exception const & e, M && ... m ) + handle_exception( expect & exp, std::exception const & e, M && ... m ) { if( auto err = dynamic_cast(&e) ) - handle_error(exp,*err,m...); + { + if( handle_error(exp,*err,m...) ) + return; + } else { - assert(current_error()!=0); - handle_error(exp,*current_error(),m...); + if( handle_error(exp,error(),m...) ) + return; } + throw; } template void @@ -47,10 +48,7 @@ boost if( auto err = dynamic_cast(&e) ) diagnostic_print(os,exp,*err); else - { - assert(current_error()!=0); - diagnostic_print(os,exp); - } + diagnostic_print(os,exp,error::peek_next_error()); } } } diff --git a/include/boost/leaf/exception_capture.hpp b/include/boost/leaf/exception_capture.hpp index cb9f8c1..4654fc5 100644 --- a/include/boost/leaf/exception_capture.hpp +++ b/include/boost/leaf/exception_capture.hpp @@ -22,20 +22,16 @@ boost { class captured_exception: - public std::exception + public std::exception, + error_capture { std::exception_ptr ex_; - error_capture cap_; + bool has_error_; public: - captured_exception( std::exception_ptr && ex, error_capture && cap ) noexcept: + captured_exception( std::exception_ptr && ex, error_capture && cap, bool has_error ) noexcept: + error_capture(std::move(cap)), ex_(std::move(ex)), - cap_(std::move(cap)) - { - assert(ex_); - } - explicit - captured_exception( std::exception_ptr && ex ) noexcept: - ex_(std::move(ex)) + has_error_(has_error) { assert(ex_); } @@ -43,14 +39,19 @@ boost void rethrow_original_exception() { - set_current_error(cap_.propagate()); + if( !has_error_ ) + { + set_error(error::peek_next_error()); + has_error_ = true; + } + propagate(); std::rethrow_exception(ex_); } friend void diagnostic_print( std::ostream & os, captured_exception const & ce ) { - diagnostic_print(os,ce.cap_); + diagnostic_print(os,static_cast(ce)); } }; template @@ -75,14 +76,11 @@ boost } catch( error const & e ) { - throw captured_exception(std::current_exception(),capture(exp,e)); + throw captured_exception(std::current_exception(),capture(exp,e),true); } catch(...) { - if( error const * e = current_error() ) - throw captured_exception(std::current_exception(),capture(exp,*e)); - else - throw captured_exception(std::current_exception()); + throw captured_exception(std::current_exception(),capture(exp,error()),false); } } }; diff --git a/include/boost/leaf/expect.hpp b/include/boost/leaf/expect.hpp index 4febcd2..ad92a78 100644 --- a/include/boost/leaf/expect.hpp +++ b/include/boost/leaf/expect.hpp @@ -43,36 +43,36 @@ boost static const int value = type_index::value; }; //////////////////////////////////////// - template - struct all_available_slot; - template + template + struct slots_subset; + template struct - all_available_slot + slots_subset { static bool - check( Tuple const & tup, error const & e ) noexcept + have_values( SlotsTuple const & tup, error const & e ) noexcept { - auto & sl = std::get::value>(tup); - return sl.has_value() && sl.value().e==e && all_available_slot::check(tup,e); + auto & sl = std::get::value>(tup); + return sl.has_value() && sl.value().e==e && slots_subset::have_values(tup,e); } }; - template + template struct - all_available_slot + slots_subset { - static bool check( Tuple const &, error const & ) noexcept { return true; } + static bool have_values( SlotsTuple const &, error const & ) noexcept { return true; } }; //////////////////////////////////////// template struct - tuple_print_slot + tuple_for_each { static void print( std::ostream & os, Tuple const & tup ) { - tuple_print_slot::print(os,tup); + tuple_for_each::print(os,tup); auto & opt = std::get(tup); if( opt.has_value() ) { @@ -85,7 +85,7 @@ boost void print( std::ostream & os, Tuple const & tup, error const & e ) { - tuple_print_slot::print(os,tup,e); + tuple_for_each::print(os,tup,e); auto & opt = std::get(tup); if( opt.has_value() ) { @@ -94,13 +94,23 @@ boost os << std::endl; } } + static + void + clear_error( Tuple & tup, error const & e ) noexcept + { + tuple_for_each::clear_error(tup,e); + auto & opt = std::get(tup); + if( opt.has_value() && opt.value().e==e ) + opt.reset(); + } }; template struct - tuple_print_slot<0,Tuple> + tuple_for_each<0,Tuple> { - static void print( std::ostream &, Tuple const & ) { } - static void print( std::ostream &, Tuple const &, error const & ) { } + static void print( std::ostream &, Tuple const & ) noexcept { } + static void print( std::ostream &, Tuple const &, error const & ) noexcept { } + static void clear_error( Tuple &, error const & ) noexcept { } }; //////////////////////////////////////// template @@ -108,19 +118,26 @@ boost convert_optional( slot && x, error const & e ) noexcept { if( x.has_value() && x.value().e==e ) - return optional(std::move(x.extract_value().v)); + return optional(std::move(x).value().v); else return optional(); } } + class error_capture; + + template + struct + dependent_type + { + typedef leaf::error_capture error_capture; + }; + template class expect; template decltype(P::value) const * peek( expect const &, error const & ) noexcept; - class error_capture; - template class expect @@ -130,13 +147,6 @@ boost template friend decltype(P::value) const * leaf::peek( expect const &, error const & ) noexcept; - template - struct - dependent_type - { - typedef leaf::error_capture error_capture; - }; - expect( expect const & ) = delete; expect & operator=( expect const & ) = delete; @@ -144,10 +154,10 @@ boost template int - unwrap( leaf_detail::match_fn const & m, error const & e, bool & matched ) const noexcept + unwrap( leaf_detail::match_fn const & m, error const & e, bool & matched ) const { using namespace leaf_detail; - if( !matched && (matched=all_available_slot...>::check(s_,e)) ) + if( !matched && (matched=slots_subset...>::have_values(s_,e)) ) (void) m.f( *leaf::peek(*this,e)... ); return 42; } @@ -157,39 +167,41 @@ boost { using namespace leaf_detail; if( !matched ) - matched = all_available_slot...>::check(s_,e); + matched = slots_subset...>::have_values(s_,e); return 42; } public: expect() noexcept { - leaf_detail::clear_current_error(); } ~expect() noexcept { } template friend - void - handle_error( expect const & exp, error const & e, M && ... m ) + bool + handle_error( expect & exp, error const & e, M && ... m ) noexcept { bool matched = false; { using _ = int[ ]; (void) _ { 42, exp.unwrap(m,e,matched)... }; } - if( !matched ) - throw_exception(mismatch_error(),e); - leaf_detail::clear_current_error(e); + if( matched ) + { + leaf_detail::tuple_for_each::clear_error(exp.s_,e); + error::clear_next_error(); + } + return matched; } friend void diagnostic_print( std::ostream & os, expect const & exp ) { - leaf_detail::tuple_print_slot::print(os,exp.s_); + leaf_detail::tuple_for_each::print(os,exp.s_); } friend void diagnostic_print( std::ostream & os, expect const & exp, error const & e ) { - leaf_detail::tuple_print_slot::print(os,exp.s_,e); + leaf_detail::tuple_for_each::print(os,exp.s_,e); } friend typename dependent_type::error_capture @@ -201,7 +213,6 @@ boost std::make_tuple( convert_optional( std::move(std::get,decltype(exp.s_)>::value>(exp.s_)),e)...)); - clear_current_error(e); return cap; } }; diff --git a/include/boost/leaf/preload.hpp b/include/boost/leaf/preload.hpp deleted file mode 100644 index b598faf..0000000 --- a/include/boost/leaf/preload.hpp +++ /dev/null @@ -1,108 +0,0 @@ -//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) - -#ifndef UUID_8F1C53BEB39F11E8A1C5B6F3E99C4353 -#define UUID_8F1C53BEB39F11E8A1C5B6F3E99C4353 - -#include -#include -#include - -namespace -boost - { - namespace - leaf - { - namespace - leaf_detail - { - template struct can_haz_call { static constexpr bool value=false; }; - template struct can_haz_call()(), void())> { static constexpr bool value=true; }; - template ::value> - struct - defer_dispatch - { - static - void - propagate_( error const & e, T && x ) noexcept - { - e.propagate(std::move(x)); - } - }; - template - struct - defer_dispatch - { - static - void - propagate_( error const & e, F && x ) noexcept - { - e.propagate(std::forward(x)()); - } - }; - template - struct - propagate_meta - { - static - void - propagate( error const & e, Tuple && t ) noexcept - { - typedef typename std::tuple_element::type ith_type; - defer_dispatch::propagate_(e,std::move(std::get(std::move(t)))); - propagate_meta::propagate(e,std::move(t)); - } - }; - template - struct - propagate_meta<0,Tuple> - { - static void propagate( error const &, Tuple && ) noexcept { } - }; - template - class - preloaded - { - preloaded( preloaded const & ) = delete; - preloaded & operator=( preloaded const & ) = delete; - typedef std::tuple::type>::type...> tuple_type; - optional to_propagate_; - public: - template - explicit - preloaded( U && ... a ): - to_propagate_(tuple_type(std::forward(a)...)) - { - } - preloaded( preloaded && x ) noexcept: - to_propagate_(std::move(x.to_propagate_)) - { - assert(!x.to_propagate_.has_value()); - } - ~preloaded() noexcept - { - if( to_propagate_.has_value() ) - if( error const * e = current_error() ) - propagate_meta::propagate(*e,to_propagate_.extract_value()); - } - void - cancel() noexcept - { - to_propagate_.reset(); - } - }; - } - template - leaf_detail::preloaded - preload( T && ... a ) - { - return leaf_detail::preloaded(std::forward(a)...); - } - } - } - -#endif diff --git a/include/boost/leaf/result.hpp b/include/boost/leaf/result.hpp index a935f7f..6e0be4c 100644 --- a/include/boost/leaf/result.hpp +++ b/include/boost/leaf/result.hpp @@ -9,9 +9,8 @@ #include -#define LEAF_ERROR ::boost::leaf::error(ei_SOURCE_LOCATION) -#define LEAF_CHECK(v,r) auto _r_##v = r; if( !_r_##v ) return _r_##v.error(); auto & v = *_r_##v -#define LEAF_CHECK_(r) {auto _r_##v = r; if( !_r_##v ) return _r_##v.error();} +#define LEAF_AUTO(v,r) auto _r_##v = r; if( !_r_##v ) return _r_##v.error(); auto & v = *_r_##v +#define LEAF_CHECK(r) {auto _r_##v = r; if( !_r_##v ) return _r_##v.error();} namespace boost @@ -266,16 +265,16 @@ boost } template friend - void - handle_error( expect const & exp, result & r, M && ... m ) + bool + handle_error( expect & exp, result & r, M && ... m ) noexcept { assert(!r); if( r.which_==result::variant::err ) - handle_error(exp,r.err_,m...); + return handle_error(exp,r.err_,m...); else { assert(r.which_==result::variant::cap); - handle_error(r.cap_,m...); + return handle_error(r.cap_,m...); } } template @@ -340,11 +339,11 @@ boost } template friend - void - handle_error( expect const & exp, result & r, M && ... m ) + bool + handle_error( expect & exp, result & r, M && ... m ) noexcept { result & rb = r; - handle_error(exp,rb,m...); + return handle_error(exp,rb,m...); } template friend diff --git a/include/boost/leaf/throw_exception.hpp b/include/boost/leaf/throw_exception.hpp index 5a0f4f7..1232da9 100644 --- a/include/boost/leaf/throw_exception.hpp +++ b/include/boost/leaf/throw_exception.hpp @@ -18,11 +18,6 @@ boost namespace leaf { - class - mismatch_error: - public std::exception - { - }; namespace leaf_detail { @@ -33,29 +28,13 @@ boost public Ex, public error { - exception( exception const & )=delete; - exception & operator=( exception const & )=delete; - bool moved_; public: exception( Ex && ex, error && e ) noexcept: Ex(std::move(ex)), - error(std::move(e)), - moved_(false) + error(std::move(e)) { enforce_std_exception(*this); } - exception( exception && x ) noexcept: - Ex(std::move(static_cast(x))), - error(std::move(static_cast(x))), - moved_(false) - { - x.moved_ = true; - } - ~exception() - { - if( !moved_ ) - clear_current_error(*this); - } }; } template diff --git a/meson.build b/meson.build index c926b7a..15e8ca8 100644 --- a/meson.build +++ b/meson.build @@ -30,7 +30,6 @@ tests = [ '_hpp_exception_capture_test', '_hpp_exception_test', '_hpp_expect_test', - '_hpp_preload_test', '_hpp_result_test', '_hpp_throw_exception_test', 'basic_test', @@ -39,7 +38,6 @@ tests = [ 'error_test', 'exception_capture_test', 'exception_test', - 'foreign_exception_test', 'multiple_errors_test', 'optional_test', 'preload_test', diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 6e1be6d..3a5294f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -21,7 +21,6 @@ run _hpp_error_test.cpp ; run _hpp_exception_capture_test.cpp ; run _hpp_exception_test.cpp ; run _hpp_expect_test.cpp ; -run _hpp_preload_test.cpp ; run _hpp_result_test.cpp ; run _hpp_throw_exception_test.cpp ; run basic_test.cpp ; @@ -30,7 +29,6 @@ run error_capture_test.cpp ; run error_test.cpp ; run exception_capture_test.cpp : : : multi ; run exception_test.cpp ; -run foreign_exception_test.cpp ; run multiple_errors_test.cpp ; run optional_test.cpp ; run preload_test.cpp ; diff --git a/test/_hpp_preload_test.cpp b/test/_hpp_preload_test.cpp deleted file mode 100644 index a865538..0000000 --- a/test/_hpp_preload_test.cpp +++ /dev/null @@ -1,9 +0,0 @@ -//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 -#include -int main() { return 0; } diff --git a/test/basic_test.cpp b/test/basic_test.cpp index ca015c8..643a7f1 100644 --- a/test/basic_test.cpp +++ b/test/basic_test.cpp @@ -39,9 +39,7 @@ int main() { leaf::expect,info<2>,info<4>> exp0; - BOOST_TEST(!leaf::current_error()); leaf::error e0 = f4(); - BOOST_TEST(*leaf::current_error()==e0); { int const * p = leaf::peek>(exp0,e0); BOOST_TEST(p && *p==1); @@ -51,7 +49,6 @@ main() BOOST_TEST(p && *p==2); } BOOST_TEST(!leaf::peek>(exp0,e0)); - BOOST_TEST(*leaf::current_error()==e0); leaf::expect,info<2>,info<4>> exp; leaf::error e1 = f4(); { @@ -66,7 +63,6 @@ main() BOOST_TEST(!leaf::peek>(exp,e0)); BOOST_TEST(!leaf::peek>(exp,e0)); BOOST_TEST(!leaf::peek>(exp,e0)); - BOOST_TEST(*leaf::current_error()==e1); { int const * p = leaf::peek>(exp,e1); BOOST_TEST(p && *p==1); @@ -76,16 +72,7 @@ main() BOOST_TEST(p && *p==2); } BOOST_TEST(!leaf::peek>(exp,e1)); - try - { - handle_error(exp,e1,leaf::match,info<2>,info<4>>( [ ](int,int,int) { } )); - BOOST_TEST(false); - } - catch( - leaf::mismatch_error const & e ) - { - BOOST_TEST(*leaf::current_error()==dynamic_cast(e)); - } + BOOST_TEST( !handle_error(exp,e1,leaf::match,info<2>,info<4>>( [ ](int,int,int) { } )) ); leaf::error e2 = f4(); { int const * p = leaf::peek>(exp,e2); @@ -96,10 +83,9 @@ main() BOOST_TEST(p && *p==2); } BOOST_TEST(!leaf::peek>(exp,e2)); - BOOST_TEST(*leaf::current_error()==e2); { int c1=0, c2=0, c3=0; - handle_error( exp, e2, + BOOST_TEST( handle_error( exp, e2, leaf::match,info<2>,info<4>>( [&c1]( int, int, int ) { ++c1; @@ -113,22 +99,21 @@ main() BOOST_TEST(i1==1); BOOST_TEST(i2==2); ++c3; - } ) ); + } ) ) ); BOOST_TEST(c1==0); BOOST_TEST(c2==0); BOOST_TEST(c3==1); } { int c=0; - handle_error( exp0, e0, + BOOST_TEST( handle_error( exp0, e0, leaf::match,info<1>>( [&c]( int i2,int i1 ) { BOOST_TEST(i1==1); BOOST_TEST(i2==2); ++c; - } ) ); + } ) ) ); BOOST_TEST(c==1); } - BOOST_TEST(!leaf::current_error()); return boost::report_errors(); } diff --git a/test/diagnostic_print_test.cpp b/test/diagnostic_print_test.cpp index c4b5bad..3d9f474 100644 --- a/test/diagnostic_print_test.cpp +++ b/test/diagnostic_print_test.cpp @@ -79,8 +79,8 @@ main() printable_info_non_printable_payload, non_printable_info_printable_payload, non_printable_info_non_printable_payload, - leaf::ei_errno, - leaf::ei_source_location + leaf::e_errno, + leaf::e_source_location > exp; try { @@ -91,12 +91,11 @@ main() printable_info_non_printable_payload(), non_printable_info_printable_payload(), non_printable_info_non_printable_payload(), - leaf::ei_errno{ENOENT} ); + leaf::e_errno{ENOENT} ); } catch( my_error & e ) { - handle_error( exp, e, leaf::match<>([ ]{ }) ); std::ostringstream st; current_exception_diagnostic_print(st,exp); std::string s = st.str(); @@ -107,6 +106,7 @@ main() BOOST_TEST(s.find("*** printable_info_printable_payload printed printable_payload ***")!=s.npos); BOOST_TEST(s.find(") in function")!=s.npos); std::cout << s; + handle_exception( exp, e, leaf::match<>() ); } } return boost::report_errors(); diff --git a/test/error_capture_test.cpp b/test/error_capture_test.cpp index 60ff944..ce4a0db 100644 --- a/test/error_capture_test.cpp +++ b/test/error_capture_test.cpp @@ -47,7 +47,6 @@ main() { leaf::error_capture e1 = make_capture(); BOOST_TEST(e1); - BOOST_TEST(!leaf::current_error()); { int const * p = leaf::peek>(e1); BOOST_TEST(p && *p==1); @@ -77,10 +76,9 @@ main() BOOST_TEST(p && *p==2); } BOOST_TEST(!leaf::peek>(exp,e2)); - BOOST_TEST(*leaf::current_error()==e2); { int c1=0, c2=0; - handle_error( exp, e2, + BOOST_TEST( handle_error( exp, e2, leaf::match,info<2>,info<4>>( [&c1]( int, int, int ) { ++c1; @@ -90,14 +88,13 @@ main() BOOST_TEST(i1==1); BOOST_TEST(i2==2); ++c2; - } ) ); + } ) ) ); BOOST_TEST(c1==0); BOOST_TEST(c2==1); } - BOOST_TEST(!leaf::current_error()); { int c1=0, c2=0, c3=0; - handle_error( e1, + BOOST_TEST( handle_error( e1, leaf::match,info<2>,info<3>>( [&c1]( int, int, int ) { ++c1; @@ -111,11 +108,14 @@ main() BOOST_TEST(i1==1); BOOST_TEST(i2==2); ++c3; - } ) ); + } ) ) ); BOOST_TEST(c1==0); BOOST_TEST(c2==0); BOOST_TEST(c3==1); } - BOOST_TEST(!e1); + BOOST_TEST( handle_error( e1, + leaf::match,info<2>,info<3>>(), + leaf::match,info<2>,info<4>>(), + leaf::match,info<1>>() ) ); return boost::report_errors(); } diff --git a/test/error_test.cpp b/test/error_test.cpp index 78c66ce..3b297f7 100644 --- a/test/error_test.cpp +++ b/test/error_test.cpp @@ -24,26 +24,27 @@ leaf::error f2() { leaf::expect> exp; - leaf::error e=f1(); - BOOST_TEST(*leaf::current_error()==e); - return e.propagate( info<2>{2} ); + return f1().propagate( info<2>{2} ); } leaf::error f3() { leaf::expect,info<3>> exp; - leaf::error e=f2(); - BOOST_TEST(*leaf::current_error()==e); - return e.propagate( info<4>{4} ); + return f2().propagate( info<4>{4} ); } leaf::error f4() { leaf::expect,info<2>,info<3>,info<4>> exp; - leaf::error e=f3(); - BOOST_TEST(*leaf::current_error()==e); + { + leaf::error e = f3(); + BOOST_TEST( handle_error( exp, e, + leaf::match,info<2>,info<3>,info<4>>(), + leaf::match,info<2>,info<4>>() ) ); + } + leaf::error e = f3(); int c1=0, c2=0; - handle_error( exp, e, + BOOST_TEST( handle_error( exp, e, leaf::match,info<2>,info<3>,info<4>>( [&c1]( int, int, int, int ) { ++c1; @@ -54,10 +55,9 @@ f4() BOOST_TEST(i2==2); BOOST_TEST(i4==4); ++c2; - } ) ); + } ) ) ); BOOST_TEST(c1==0); BOOST_TEST(c2==1); - BOOST_TEST(!leaf::current_error()); return leaf::error(); } int @@ -65,7 +65,6 @@ main() { leaf::expect,info<3>,info<4>> exp; leaf::error e=f4(); - BOOST_TEST(*leaf::current_error()==e); BOOST_TEST(!leaf::peek>(exp,e)); BOOST_TEST(!leaf::peek>(exp,e)); BOOST_TEST(!leaf::peek>(exp,e)); diff --git a/test/exception_capture_test.cpp b/test/exception_capture_test.cpp index 87a0157..54c4ee9 100644 --- a/test/exception_capture_test.cpp +++ b/test/exception_capture_test.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -17,7 +16,7 @@ namespace leaf = boost::leaf; struct my_error: std::exception { }; -template struct my_info { int value; }; +template struct info { int value; }; struct fut_info @@ -40,7 +39,7 @@ launch_tasks( int task_count, F && f ) int const res = (rand()%10) - 5; return fut_info { a, b, res, std::async( std::launch::async, [f,a,b,res] { - auto wrapper = leaf::capture_exception,my_info<2>,my_info<3>>(std::move(f)); + auto wrapper = leaf::capture_exception,info<2>,info<3>>(std::move(f)); return wrapper( a, b, res ); } ) }; } ); @@ -55,7 +54,7 @@ test( int task_count, F && f ) noexcept { using namespace leaf::leaf_detail; f.fut.wait(); - leaf::expect,my_info<2>,my_info<4>> exp; + leaf::expect,info<2>,info<4>> exp; try { int r = leaf::get(f.fut); @@ -65,11 +64,14 @@ test( int task_count, F && f ) noexcept catch( my_error const & e ) { - handle_error( exp, e, leaf::match,my_info<2>>( [&f]( int x1, int x2 ) + int c=0; + handle_exception( exp, e, leaf::match,info<2>>( [&f,&c]( int x1, int x2 ) { BOOST_TEST(x1==f.a); BOOST_TEST(x2==f.b); + ++c; } ) ); + BOOST_TEST(c==1); } } } @@ -81,7 +83,7 @@ main() if( res>=0 ) return res; else - leaf::throw_exception( my_error(), my_info<1>{a}, my_info<2>{b}, my_info<3>{}) ; + leaf::throw_exception( my_error(), info<1>{a}, info<2>{b}, info<3>{}) ; } ); test( 42, [ ]( int a, int b, int res ) { @@ -89,7 +91,7 @@ main() return res; else { - auto propagate = leaf::preload( my_info<1>{a}, my_info<2>{b}, my_info<3>{} ); + leaf::preload( info<1>{a}, info<2>{b}, info<3>{} ); throw my_error(); } } ); diff --git a/test/exception_test.cpp b/test/exception_test.cpp index 65e2d50..d81aaae 100644 --- a/test/exception_test.cpp +++ b/test/exception_test.cpp @@ -6,13 +6,14 @@ #include #include -#include #include namespace leaf = boost::leaf; struct my_error: std::exception { }; +std::function thrower; + template struct info @@ -22,7 +23,7 @@ info void f1() { - return leaf::throw_exception( my_error(), info<1>{1} ); + thrower(); } void f2() @@ -35,16 +36,20 @@ f2() } catch( leaf::error const & e ) { - BOOST_TEST(e==*leaf::current_error()); e.propagate( info<2>{2} ); throw; } + catch( ... ) + { + leaf::preload( info<2>{2} ); + throw; + } } void f3() { leaf::expect,info<3>> exp; - auto propagate = leaf::preload( info<4>{4} ); + leaf::preload( info<4>{4} ); f2(); } void @@ -59,9 +64,8 @@ f4() catch( my_error const & e ) { - BOOST_TEST(*leaf::current_error()==*dynamic_cast(&e)); int c1=0, c2=0; - handle_error( exp, e, + handle_exception( exp, e, leaf::match,info<2>,info<3>,info<4>>( [&c1]( int, int, int, int ) { ++c1; @@ -75,13 +79,13 @@ f4() } ) ); BOOST_TEST(c1==0); BOOST_TEST(c2==1); - BOOST_TEST(!leaf::current_error()); } leaf::throw_exception( my_error() ); } -int -main() +void +test( std::function const & f ) { + thrower = f; leaf::expect,info<3>,info<4>> exp; try { @@ -91,7 +95,6 @@ main() catch( my_error const & e ) { - BOOST_TEST(*leaf::current_error()==*dynamic_cast(&e)); BOOST_TEST(!leaf::peek>(exp,e)); BOOST_TEST(!leaf::peek>(exp,e)); BOOST_TEST(!leaf::peek>(exp,e)); @@ -100,5 +103,11 @@ main() BOOST_TEST(leaf::leaf_detail::tl_slot_ptr>()!=0); BOOST_TEST(leaf::leaf_detail::tl_slot_ptr>()!=0); } + } +int +main() + { + test( [ ] { leaf::throw_exception( my_error(), info<1>{1} ); } ); + test( [ ] { leaf::preload(info<1>{1}); throw my_error(); } ); return boost::report_errors(); } diff --git a/test/foreign_exception_test.cpp b/test/foreign_exception_test.cpp deleted file mode 100644 index 29c6eed..0000000 --- a/test/foreign_exception_test.cpp +++ /dev/null @@ -1,109 +0,0 @@ -//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 -#include -#include -#include - -namespace leaf = boost::leaf; - -struct my_error: std::exception { }; - -leaf::error the_error; - -template -struct -info - { - int value; - }; -void -f1() - { - auto propagate = leaf::preload( info<1>{1} ); - throw my_error(); - } -void -f2() - { - leaf::expect> exp; - try - { - f1(); - BOOST_TEST(false); - } - catch(...) - { - leaf::error ce = *leaf::current_error(); - BOOST_TEST(ce!=the_error); - the_error = ce; - leaf::propagate( info<2>{2} ); - throw; - } - } -void -f3() - { - leaf::expect,info<3>> exp; - auto propagate = leaf::preload( info<4>{4} ); - f2(); - } -void -f4() - { - leaf::expect,info<2>,info<3>,info<4>> exp; - try - { - f3(); - BOOST_TEST(false); - } - catch( - my_error const & e ) - { - BOOST_TEST(*leaf::current_error()==the_error); - int c1=0, c2=0; - handle_error( exp, e, - leaf::match,info<2>,info<3>,info<4>>( [&c1]( int, int, int, int ) - { - ++c1; - } ), - leaf::match,info<2>,info<4>>( [&c2]( int i1, int i2, int i4 ) - { - BOOST_TEST(i1==1); - BOOST_TEST(i2==2); - BOOST_TEST(i4==4); - ++c2; - } ) ); - BOOST_TEST(c1==0); - BOOST_TEST(c2==1); - BOOST_TEST(!leaf::current_error()); - } - throw my_error(); - } -int -main() - { - leaf::expect,info<3>,info<4>> exp; - try - { - f4(); - BOOST_TEST(false); - } - catch( - my_error const & e ) - { - BOOST_TEST(*leaf::current_error()!=the_error); - BOOST_TEST(!leaf::peek>(exp,e)); - BOOST_TEST(!leaf::peek>(exp,e)); - BOOST_TEST(!leaf::peek>(exp,e)); - BOOST_TEST(leaf::leaf_detail::tl_slot_ptr>()==0); - BOOST_TEST(leaf::leaf_detail::tl_slot_ptr>()!=0); - BOOST_TEST(leaf::leaf_detail::tl_slot_ptr>()!=0); - BOOST_TEST(leaf::leaf_detail::tl_slot_ptr>()!=0); - } - return boost::report_errors(); - } diff --git a/test/multiple_errors_test.cpp b/test/multiple_errors_test.cpp index f763d88..8fd8e72 100644 --- a/test/multiple_errors_test.cpp +++ b/test/multiple_errors_test.cpp @@ -30,10 +30,9 @@ main() { leaf::expect,info<2>,info<3>,info<4>> exp; leaf::error e1=f12(); - handle_error( exp, e1, leaf::match<>() ); leaf::error e2=f34(); int e1c1=0, e1c2=0; - handle_error( exp, e1, + BOOST_TEST( handle_error( exp, e1, leaf::match,info<4>>( [&e1c1]( int, int ) { ++e1c1; @@ -43,11 +42,11 @@ main() BOOST_TEST(i1==1); BOOST_TEST(i2==2); ++e1c2; - } ) ); + } ) ) ); BOOST_TEST(e1c1==0); BOOST_TEST(e1c2==1); int e2c1=0, e2c2=0; - handle_error( exp, e2, + BOOST_TEST( handle_error( exp, e2, leaf::match,info<2>>( [&e2c1]( int, int ) { ++e2c1; @@ -57,7 +56,7 @@ main() BOOST_TEST(i3==3); BOOST_TEST(i4==4); ++e2c2; - } ) ); + } ) ) ); BOOST_TEST(e2c1==0); BOOST_TEST(e2c2==1); return boost::report_errors(); diff --git a/test/optional_test.cpp b/test/optional_test.cpp index 8ad21d7..13b3006 100644 --- a/test/optional_test.cpp +++ b/test/optional_test.cpp @@ -287,7 +287,7 @@ run_tests() optional x(my_info(42)); BOOST_TEST(object_count==1); BOOST_TEST(value_count==1); - my_info a = x.extract_value(); + my_info a = std::move(x).value(); BOOST_TEST(object_count==1); BOOST_TEST(value_count==1); BOOST_TEST(!x.has_value()); diff --git a/test/preload_test.cpp b/test/preload_test.cpp index d09ab98..86cbba5 100644 --- a/test/preload_test.cpp +++ b/test/preload_test.cpp @@ -4,7 +4,6 @@ //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 #include #include @@ -23,25 +22,24 @@ info { int value; }; -void +leaf::error f0() { - auto propagate = leaf::preload( info<0>{0} ); + leaf::preload( info<0>{0} ); + return leaf::error( info<2>{2} ); } leaf::error f1() { - f0(); global = 0; - auto propagate = leaf::preload( info<1>{1}, [ ] { return info<42>{get_global()}; } ); + leaf::preload( info<1>{1} ); + auto propagate = leaf::defer( [ ] { return info<42>{get_global()}; } ); global = 42; - return leaf::error( info<2>{2} ); + return f0(); } leaf::error f2() { - auto propagate = leaf::preload( info<3>{3} ); - propagate.cancel(); return f1().propagate( info<4>{4} ); } int @@ -51,7 +49,7 @@ main() leaf::error e = f2(); BOOST_TEST(!leaf::peek>(exp,e)); int c=0; - handle_error( exp, e, + BOOST_TEST( handle_error( exp, e, leaf::match,info<1>,info<2>,info<4>>( [&c]( int i42, int i1, int i2, int i4 ) { BOOST_TEST(i42==42); @@ -59,7 +57,7 @@ main() BOOST_TEST(i2==2); BOOST_TEST(i4==4); ++c; - } ) ); + } ) ) ); BOOST_TEST(c==1); return boost::report_errors(); } diff --git a/test/result_capture_test.cpp b/test/result_capture_test.cpp index ca02814..ec432c9 100644 --- a/test/result_capture_test.cpp +++ b/test/result_capture_test.cpp @@ -14,7 +14,7 @@ namespace leaf = boost::leaf; -template struct my_info { int value; }; +template struct info { int value; }; struct fut_info @@ -37,7 +37,7 @@ launch_tasks( int task_count, F f ) int const res = (rand()%10) - 5; return fut_info { a, b, res, std::async( std::launch::async, [f,a,b,res] { - leaf::expect,my_info<2>,my_info<3>> exp; + leaf::expect,info<2>,info<3>> exp; return capture(exp,f(a,b,res)); } ) }; } ); @@ -51,13 +51,13 @@ main() if( res>=0 ) return res; else - return leaf::error(my_info<1>{a},my_info<2>{b},my_info<3>{}); + return leaf::error(info<1>{a},info<2>{b},info<3>{}); } ); for( auto & f : fut ) { using namespace leaf::leaf_detail; f.fut.wait(); - leaf::expect,my_info<2>,my_info<4>> exp; + leaf::expect,info<2>,info<4>> exp; if( leaf::result r = f.fut.get() ) { BOOST_TEST(*r>=0); @@ -65,11 +65,14 @@ main() } else { - handle_error( exp, r, leaf::match,my_info<2>>( [&f]( int x1, int x2 ) + int c=0; + BOOST_TEST( handle_error( exp, r, leaf::match,info<2>>( [&f,&c]( int x1, int x2 ) { BOOST_TEST(x1==f.a); BOOST_TEST(x2==f.b); - } ) ); + ++c; + } ) ) ); + BOOST_TEST(c==1); } } return boost::report_errors(); diff --git a/test/result_test.cpp b/test/result_test.cpp index f495b6a..df59d76 100644 --- a/test/result_test.cpp +++ b/test/result_test.cpp @@ -6,7 +6,6 @@ #include #include -#include #include namespace leaf = boost::leaf; @@ -36,16 +35,13 @@ f2( bool success ) if( leaf::result r=f1(success) ) return r; else - { - BOOST_TEST(*leaf::current_error()==r.error()); return r.error( info<2>{2} ); - } } leaf::result f3( bool success ) { leaf::expect,info<3>> exp; - auto propagate = leaf::preload( info<4>{4} ); + leaf::preload( info<4>{4} ); return f2(success); } leaf::result @@ -56,9 +52,8 @@ f4( bool success ) return r; else { - BOOST_TEST(*leaf::current_error()==r.error()); int c1=0, c2=0; - handle_error( exp, r, + BOOST_TEST( handle_error( exp, r, leaf::match,info<2>,info<3>,info<4>>( [&c1]( int, int, int, int ) { ++c1; @@ -69,10 +64,9 @@ f4( bool success ) BOOST_TEST(i2==2); BOOST_TEST(i4==4); ++c2; - } ) ); + } ) ) ); BOOST_TEST(c1==0); BOOST_TEST(c2==1); - BOOST_TEST(!leaf::current_error()); return leaf::error(); } } @@ -84,7 +78,6 @@ main() leaf::result r=f4(false); BOOST_TEST(!r); leaf::error e = r.error(); - BOOST_TEST(*leaf::current_error()==e); BOOST_TEST(!leaf::peek>(exp,e)); BOOST_TEST(!leaf::peek>(exp,e)); BOOST_TEST(!leaf::peek>(exp,e)); diff --git a/test/result_void_capture_test.cpp b/test/result_void_capture_test.cpp index 7451db6..fdb8e20 100644 --- a/test/result_void_capture_test.cpp +++ b/test/result_void_capture_test.cpp @@ -14,7 +14,7 @@ namespace leaf = boost::leaf; -template struct my_info { int value; }; +template struct info { int value; }; struct fut_info @@ -37,7 +37,7 @@ launch_tasks( int task_count, F f ) int const res = (rand()%10) - 5; return fut_info { a, b, res, std::async( std::launch::async, [f,a,b,res] { - leaf::expect,my_info<2>,my_info<3>> exp; + leaf::expect,info<2>,info<3>> exp; return capture(exp,f(a,b,res)); } ) }; } ); @@ -51,23 +51,26 @@ main() if( res>=0 ) return { }; else - return leaf::error(my_info<1>{a},my_info<2>{b},my_info<3>{}); + return leaf::error(info<1>{a},info<2>{b},info<3>{}); } ); for( auto & f : fut ) { using namespace leaf::leaf_detail; f.fut.wait(); - leaf::expect,my_info<2>,my_info<4>> exp; + leaf::expect,info<2>,info<4>> exp; if( leaf::result r = f.fut.get() ) { } else { - handle_error( exp, r, leaf::match,my_info<2>>( [&f]( int x1, int x2 ) + int c=0; + BOOST_TEST( handle_error( exp, r, leaf::match,info<2>>( [&f,&c]( int x1, int x2 ) { BOOST_TEST(x1==f.a); BOOST_TEST(x2==f.b); - } ) ); + ++c; + } ) ) ); + BOOST_TEST(c==1); } } return boost::report_errors();