From 2b306e5491e16394ef01a23e7e536f1916cc79c0 Mon Sep 17 00:00:00 2001 From: Emil Dotchevski Date: Sun, 21 Oct 2018 00:07:33 -0700 Subject: [PATCH] Major rewrite --- .vscode/launch.json | 2 +- README.adoc | 40 +- example/capture_eh.cpp | 16 +- example/capture_result.cpp | 20 +- example/print_file_eh.cpp | 9 +- example/print_file_result.cpp | 11 +- include/boost/leaf/all.hpp | 11 +- include/boost/leaf/capture_exception.hpp | 94 ----- include/boost/leaf/captured_result.hpp | 85 ---- include/boost/leaf/common.hpp | 34 +- ...rrent_exception_diagnostic_information.hpp | 45 --- include/boost/leaf/detail/captured_info.hpp | 96 ----- include/boost/leaf/detail/optional.hpp | 8 +- .../{diagnostic_print.hpp => print.hpp} | 15 +- include/boost/leaf/detail/tl_slot.hpp | 198 --------- include/boost/leaf/detail/tuple.hpp | 47 +++ include/boost/leaf/diagnostic_information.hpp | 114 ------ include/boost/leaf/error.hpp | 244 +++++++++++ include/boost/leaf/error_capture.hpp | 302 ++++++++++++++ include/boost/leaf/exception.hpp | 58 +++ include/boost/leaf/exception_capture.hpp | 139 +++++++ include/boost/leaf/expect.hpp | 316 ++++++--------- include/boost/leaf/{put.hpp => preload.hpp} | 70 +--- include/boost/leaf/result.hpp | 381 +++++++++++++----- include/boost/leaf/throw_exception.hpp | 71 ++++ meson.build | 38 +- test/{hpp_put_test.cpp => _hpp_all_test.cpp} | 4 +- ...p_common_test.cpp => _hpp_common_test.cpp} | 0 ...t_test.cpp => _hpp_error_capture_test.cpp} | 4 +- ...transport_test.cpp => _hpp_error_test.cpp} | 4 +- ...st.cpp => _hpp_exception_capture_test.cpp} | 4 +- ...error_test.cpp => _hpp_exception_test.cpp} | 4 +- ...p_expect_test.cpp => _hpp_expect_test.cpp} | 0 test/_hpp_preload_test.cpp | 9 + test/_hpp_result_test.cpp | 9 + test/_hpp_throw_exception_test.cpp | 9 + test/basic_test.cpp | 135 +++++++ test/diagnostic_information_test.cpp | 110 ----- test/diagnostic_print_test.cpp | 144 ++++--- test/error_capture_test.cpp | 121 ++++++ test/error_test.cpp | 77 ++++ ...on_test.cpp => exception_capture_test.cpp} | 25 +- test/exception_test.cpp | 104 +++++ test/expect_eh_test.cpp | 121 ------ test/expect_result_test.cpp | 120 ------ test/foreign_exception_test.cpp | 109 +++++ ..._exception_diagnostic_information_test.cpp | 9 - test/hpp_diagnostic_information_test.cpp | 9 - test/multiple_errors_test.cpp | 63 +++ test/preload_test.cpp | 65 +++ test/print_test.cpp | 93 +++++ ...esult_test.cpp => result_capture_test.cpp} | 17 +- test/result_test.cpp | 96 +++++ ..._test.cpp => result_void_capture_test.cpp} | 16 +- test/tl_slot_test.cpp | 259 ------------ 55 files changed, 2448 insertions(+), 1756 deletions(-) delete mode 100644 include/boost/leaf/capture_exception.hpp delete mode 100644 include/boost/leaf/captured_result.hpp delete mode 100644 include/boost/leaf/current_exception_diagnostic_information.hpp delete mode 100644 include/boost/leaf/detail/captured_info.hpp rename include/boost/leaf/detail/{diagnostic_print.hpp => print.hpp} (81%) delete mode 100644 include/boost/leaf/detail/tl_slot.hpp create mode 100644 include/boost/leaf/detail/tuple.hpp delete mode 100644 include/boost/leaf/diagnostic_information.hpp create mode 100644 include/boost/leaf/error.hpp create mode 100644 include/boost/leaf/error_capture.hpp create mode 100644 include/boost/leaf/exception.hpp create mode 100644 include/boost/leaf/exception_capture.hpp rename include/boost/leaf/{put.hpp => preload.hpp} (52%) create mode 100644 include/boost/leaf/throw_exception.hpp rename test/{hpp_put_test.cpp => _hpp_all_test.cpp} (81%) rename test/{hpp_common_test.cpp => _hpp_common_test.cpp} (100%) rename test/{hpp_captured_result_test.cpp => _hpp_error_capture_test.cpp} (75%) rename test/{hpp_transport_test.cpp => _hpp_error_test.cpp} (78%) rename test/{hpp_capture_exception_test.cpp => _hpp_exception_capture_test.cpp} (74%) rename test/{hpp_has_current_error_test.cpp => _hpp_exception_test.cpp} (74%) rename test/{hpp_expect_test.cpp => _hpp_expect_test.cpp} (100%) create mode 100644 test/_hpp_preload_test.cpp create mode 100644 test/_hpp_result_test.cpp create mode 100644 test/_hpp_throw_exception_test.cpp create mode 100644 test/basic_test.cpp delete mode 100644 test/diagnostic_information_test.cpp create mode 100644 test/error_capture_test.cpp create mode 100644 test/error_test.cpp rename test/{capture_exception_test.cpp => exception_capture_test.cpp} (73%) create mode 100644 test/exception_test.cpp delete mode 100644 test/expect_eh_test.cpp delete mode 100644 test/expect_result_test.cpp create mode 100644 test/foreign_exception_test.cpp delete mode 100644 test/hpp_current_exception_diagnostic_information_test.cpp delete mode 100644 test/hpp_diagnostic_information_test.cpp create mode 100644 test/multiple_errors_test.cpp create mode 100644 test/preload_test.cpp create mode 100644 test/print_test.cpp rename test/{captured_result_test.cpp => result_capture_test.cpp} (73%) create mode 100644 test/result_test.cpp rename test/{captured_result_void_test.cpp => result_void_capture_test.cpp} (73%) delete mode 100644 test/tl_slot_test.cpp diff --git a/.vscode/launch.json b/.vscode/launch.json index 638fbd0..5cb39f5 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,7 +8,7 @@ "name": "(lldb) Launch", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/bld/debug/expect_ec_test", + "program": "${workspaceFolder}/bld/debug/capture_eh", "args": [ "test/Jafile.v2" ], "cwd": "${workspaceFolder}", "stopAtEntry": false, diff --git a/README.adoc b/README.adoc index 336e73b..3a388a1 100644 --- a/README.adoc +++ b/README.adoc @@ -10,7 +10,7 @@ Low-latency Error Augmentation Framework for C++11 [abstract] == Abstract -LEAF is a non-intrusive C++11 library for transporting arbitrary error information from contexts that detect and report failures, as well as from intermediate error-neutral contexts, to scopes where the error is ultimately handled. +LEAF is a non-intrusive C++11 error handling library capable of transporting arbitrary error information from contexts that detect and report failures, as well as from intermediate error-neutral contexts, to scopes where the error is ultimately handled. LEAF does not allocate dynamic memoryfootnote:[Except when transporting error info between threads, see <>.], which makes it suitable for low-latency and other performance-critical environments. It is compatible with all error handling APIs, and can be used with or without exception handling. @@ -36,30 +36,48 @@ LEAF requires a {CPP}11 compiler. See unit test matrix at https://travis-ci.org/ [[tutorial]] == Tutorial -As an example, here is a function that reads data from a file into a buffer, returns a user-defined `error` enum to indicate success or to report errors, and uses LEAF to provide additional error info: +While LEAF can be used with exception handling, let's begin with an example that works without exceptions. We'll write a program that reads a text file in a buffer and prints it to `std::cout`. First, we need an `enum` to indicate various error conditions: ==== [source,c++] ---- -error file_read( FILE & f, void * buf, int size ) { - int n = fread(buf,1,size,&f); +enum print_file_error +{ + file_open_error, + file_size_error, + file_read_error, + file_eof_error, + cout_error +}; +---- +==== - if( ferror(&f) ) { <1> - leaf::put( ei_errno { errno } ); - return file_read_error; - } +Note that we don't need a value that indicates success. That's because we will use the provided class template `<>` as a return type in functions which may fail. It can be initialized with a `T` to indicate success, or with the return value of `leaf::<>()` to report a failure. + +NOTE: `result` is a specialization of the `result` template suitable for functions which do not return a value in case of success. It can be initialized with `{ }` to indicate success, or, like any other `result` instantiation, with the return value of `<>` to indicate a failure. + +Here is a function that reads data from a file into a buffer and reports various errors which may occur: + +==== +[source,c++] +---- +leaf::result file_read( FILE & f, void * buf, int size ) +{ + int n = fread(buf,1,size,&f); + if( ferror(&f) ) <1> + return leaf::error( ei_error_code{file_read_error}, ei_errno{errno} ); if( n!=size ) <2> - return file_eof_error; + return leaf::error( ei_error_code{file_eof_error} ); - return ok; + return { }; } ---- <1> The function fails if `ferror` indicates an error. <2> It also fails if `fread` reports that it didn't read all of the data requested. ==== -In the first case, there is a relevant `errno` code, so the function uses `<>` to make it available later when the error is handled. +In the first case, we indicate `file_read_error` (on of our enumerated errors) there is a relevant `errno` code, so the function uses `<>` to make it available later when the error is handled. The second condition, while treated as a failure by our `file_read` function, is not a failure as far as `fread` is concerned, and therefore `errno` is not available. So in this case we simply return `file_eof_error`. diff --git a/example/capture_eh.cpp b/example/capture_eh.cpp index 44bf4ba..bd7415a 100644 --- a/example/capture_eh.cpp +++ b/example/capture_eh.cpp @@ -8,7 +8,7 @@ //when using exception handling to report failures. See transport_ec.cpp for the variant that doesn't //use exception handling. -#include +#include #include #include #include @@ -45,19 +45,19 @@ task_result task( bool succeed ) failure_info4{42} ); } -//Launch the specified number of asynchronous tasks. In case an asynchronous task fails, its error info -//(of the type list used to instantiate leaf::capture) is captured in a leaf::captured_result, which -//transports it to the main thread. -template +//Launch the specified number of asynchronous tasks. In case an asynchronous task throws, its error info +//(of the type list used to instantiate leaf::capture_exception) is captured and wrapped in a different exception, +//which transports it to the main thread. The original exception is then recovered by leaf::get. +template std::vector> launch_async_tasks( int thread_count ) { std::vector> fut; std::generate_n( std::inserter(fut,fut.end()), thread_count, [ ] { return std::async( std::launch::async, - leaf::capture_exception( [ ] //leaf::capture returns leaf::captured_result... + leaf::capture_exception( [ ] //returns a wrapper function for the lambda... { - return task(rand()%4); //...from the T returned by the task. + return task(rand()%4); //...which transports the E... objects. } ) ); } ); return fut; @@ -81,7 +81,7 @@ int main() try { //Instead of calling future::get we pass the future object to leaf::get. In case the future finished with an exception, - //this will rethrow that exception, after setting its captured error info. + //this will rethrow that exception, after dropping captured error info into exp. task_result r = leaf::get(f); //Success! diff --git a/example/capture_result.cpp b/example/capture_result.cpp index c5ce9e8..045c4a6 100644 --- a/example/capture_result.cpp +++ b/example/capture_result.cpp @@ -7,7 +7,7 @@ //This is a simple program that demonstrates the use of LEAF to transport error info between threads, //without using exception handling. See transport_eh.cpp for the exception-handling variant. -#include +#include #include #include #include @@ -41,18 +41,17 @@ leaf::result task( bool succeed ) } //Launch the specified number of asynchronous tasks. In case an asynchronous task fails, its error info -//(of the type list used to instantiate leaf::capture) is captured in a leaf::captured_result, which -//transports it to the main thread. -template -std::vector>> launch_async_tasks( int thread_count ) +//(initially stored in exp) is captured in a leaf::result, which transports it to the main thread. +template +std::vector>> launch_async_tasks( int thread_count ) { - std::vector>> fut; + std::vector>> fut; std::generate_n( std::inserter(fut,fut.end()), thread_count, [ ] { return std::async( std::launch::async, [ ] { - leaf::expect exp; - return task(rand()%4).capture(exp); + leaf::expect exp; + return capture(exp,task(rand()%4)); } ); } ); return fut; @@ -73,9 +72,8 @@ int main() //Storage for error info. leaf::expect exp; - //Unpack the leaf::captured_result to get a leaf::result and, - //in case of error, set its captured error info. - if( leaf::result r = f.get().get() ) + //Get the task result, check for success. + if( leaf::result r = f.get() ) { //Success! Use *r to access task_result. std::cout << "Success!" << std::endl; diff --git a/example/print_file_eh.cpp b/example/print_file_eh.cpp index 89b3eba..a3aafef 100644 --- a/example/print_file_eh.cpp +++ b/example/print_file_eh.cpp @@ -5,8 +5,8 @@ //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) //This example demonstrates the basic use of LEAF to augment error conditions with -//additional information when using exceptions to report failures. See print_file_ec.cpp -//for the variant that uses error codes. +//additional information when using exceptions to report failures. See print_file_result.cpp +//for the variant that doesn't use exceptions. #include #include @@ -14,7 +14,7 @@ namespace leaf = boost::leaf; -//We could define our own exception info types, but for this example the ones +//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; @@ -137,8 +137,9 @@ int main( int argc, char const * argv[ ] ) } catch(...) { + //This catch-all is designed to help diagnose logic errors (main should be able to deal with any failures). std::cerr << "Unknown error, cryptic information follows." << std::endl; - exp.print_current_exception_diagnostic_information(std::cerr); + current_exception_diagnostic_print(std::cerr,exp); return 4; } return 0; diff --git a/example/print_file_result.cpp b/example/print_file_result.cpp index 1ded5e3..1a4c4cb 100644 --- a/example/print_file_result.cpp +++ b/example/print_file_result.cpp @@ -5,7 +5,7 @@ //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) //This example demonstrates the basic use of LEAF to augment error conditions with -//additional information when using error codes to report failures. See print_file_eh.cpp +//additional information when using result to report failures. See print_file_eh.cpp //for the variant that uses exception handling. #include @@ -14,7 +14,7 @@ namespace leaf = boost::leaf; -//We could define our own exception info types, but for this example the ones +//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; @@ -113,7 +113,8 @@ int main( int argc, char const * argv[ ] ) { 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). + //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 ) @@ -144,9 +145,9 @@ int main( int argc, char const * argv[ ] ) } ) ); 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; - exp.print_diagnostic_information(std::cerr); + diagnostic_print(std::cerr,exp,r); return 4; } } - \ No newline at end of file diff --git a/include/boost/leaf/all.hpp b/include/boost/leaf/all.hpp index 38728a2..d4325f9 100644 --- a/include/boost/leaf/all.hpp +++ b/include/boost/leaf/all.hpp @@ -4,11 +4,12 @@ //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 -#include +#include +#include +#include +#include #include -#include +#include #include +#include diff --git a/include/boost/leaf/capture_exception.hpp b/include/boost/leaf/capture_exception.hpp deleted file mode 100644 index 17a6c53..0000000 --- a/include/boost/leaf/capture_exception.hpp +++ /dev/null @@ -1,94 +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_BC24FB98B2DE11E884419CF5AD35F1A2 -#define UUID_BC24FB98B2DE11E884419CF5AD35F1A2 - -#include -#include - -namespace -boost - { - namespace - leaf - { - namespace - leaf_detail - { - class - captured_exception - { - std::shared_ptr cap_; - std::exception_ptr ex_; - public: - captured_exception( std::shared_ptr && cap, std::exception_ptr && ex ): - cap_(std::move(cap)), - ex_(std::move(ex)) - { - assert(ex_); - } - [[noreturn]] - void - rethrow_original_exception() - { - cap_->unpack(); - std::rethrow_exception(ex_); - } - }; - template - class - wrapper_exception - { - wrapper_exception & operator=( wrapper_exception const & ) = delete; - F f_; - public: - wrapper_exception( wrapper_exception const & ) = default; - wrapper_exception( wrapper_exception && ) = default; - explicit - wrapper_exception( F && f ): - f_(std::move(f)) - { - } - template - decltype(std::declval()()) - operator()( A && ... a ) - { - expect exp; - try - { - return f_(std::forward(a)...); - } - catch(...) - { - throw captured_exception(std::shared_ptr(new captured_info_impl(extract(exp))),std::current_exception()); - } - } - }; - } - template - leaf_detail::wrapper_exception - capture_exception( F && f ) - { - return leaf_detail::wrapper_exception(std::move(f)); - } - template - decltype(std::declval().get()) - get( Future && f ) - { - try - { - return std::forward(f).get(); - } - catch( leaf_detail::captured_exception & ex ) - { - ex.rethrow_original_exception(); - } - } - } - } - -#endif diff --git a/include/boost/leaf/captured_result.hpp b/include/boost/leaf/captured_result.hpp deleted file mode 100644 index cd06339..0000000 --- a/include/boost/leaf/captured_result.hpp +++ /dev/null @@ -1,85 +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_E95BDA9ACEAA11E894618A98A659E189 -#define UUID_E95BDA9ACEAA11E894618A98A659E189 - -#include -#include - -namespace -boost - { - namespace - leaf - { - template - class - captured_result - { - friend class result; - result r_; - std::shared_ptr cap_; - explicit - captured_result( result && r ) noexcept: - r_(std::move(r)) - { - assert(r_); - } - explicit - captured_result( std::shared_ptr && cap ) noexcept: - r_(leaf_detail::error_tag()), - cap_(std::move(cap)) - { - } - public: -#ifdef _MSC_VER - captured_result() noexcept - { - } -#else - captured_result( captured_result const & ) = delete; - captured_result & operator=( captured_result const & ) = delete; - captured_result( captured_result && ) noexcept = default; -#endif - result - get() - { - if( cap_ ) - { - cap_->unpack(); - cap_.reset(); - } - return r_; - } - }; - template - template - captured_result - result:: - capture( expect & exp ) - { - using namespace leaf_detail; - if( *this ) - return captured_result(std::move(*this)); - else - return captured_result(std::shared_ptr(new captured_info_impl(extract(exp)))); - } - template - captured_result - result:: - capture( expect & exp ) - { - using namespace leaf_detail; - if( *this ) - return captured_result(std::move(*this)); - else - return captured_result(std::shared_ptr(new captured_info_impl(extract(exp)))); - } - } - } - -#endif diff --git a/include/boost/leaf/common.hpp b/include/boost/leaf/common.hpp index 0a51887..00b1785 100644 --- a/include/boost/leaf/common.hpp +++ b/include/boost/leaf/common.hpp @@ -7,20 +7,50 @@ #ifndef EBA7EF10B6F311E8AAD493990D39171A #define EBA7EF10B6F311E8AAD493990D39171A -#include +#include #include #include #include +#define LEAF_SOURCE_LOCATION ::boost::leaf::ei_source_location{::boost::leaf::ei_source_location::loc(__FILE__,__LINE__,__FUNCTION__)} + namespace boost { namespace leaf { + struct + ei_source_location + { + struct + loc + { + char const * const file; + int const line; + char const * const function; + loc( char const * file, int line, char const * function ): + file(file), + line(line), + function(function) + { + assert(file!=0); + assert(line>0); + assert(function!=0); + } + }; + loc value; + friend + std::ostream & + operator<<( std::ostream & os, ei_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 ei_errno { diff --git a/include/boost/leaf/current_exception_diagnostic_information.hpp b/include/boost/leaf/current_exception_diagnostic_information.hpp deleted file mode 100644 index ea5a06f..0000000 --- a/include/boost/leaf/current_exception_diagnostic_information.hpp +++ /dev/null @@ -1,45 +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_95126C26B8B411E8B5E01E350D39171A -#define UUID_95126C26B8B411E8B5E01E350D39171A - -#include -#include -#include - -namespace -boost - { - namespace - leaf - { - template - void - expect:: - print_current_exception_diagnostic_information( std::ostream & os ) const - { - os << "Current exception diagnostic Information:" << std::endl; - try - { - throw; - } - catch( std::exception const & ex ) - { - os << - "Exception dynamic type: " << typeid(ex).name() << - "std::exception::what(): " << ex.what() << std::endl << std::endl; - } - catch( ... ) - { - os << "Unknown exception type (not a std::exception)" << std::endl; - } - print_diagnostic_information(os); - } - } - } - -#endif diff --git a/include/boost/leaf/detail/captured_info.hpp b/include/boost/leaf/detail/captured_info.hpp deleted file mode 100644 index 42c801a..0000000 --- a/include/boost/leaf/detail/captured_info.hpp +++ /dev/null @@ -1,96 +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_C568ACFACEA811E8A23F1893A659E189 -#define UUID_C568ACFACEA811E8A23F1893A659E189 - -#include -#include - -namespace -boost - { - namespace - leaf - { - namespace - leaf_detail - { - template - struct - tuple_put - { - static - void - put( Tuple & tup ) noexcept - { - auto & opt = std::get(tup); - if( opt.has_value() ) - leaf::put(opt.extract_value()); - tuple_put::put(tup); - } - }; - template - struct - tuple_put<0,Tuple> - { - static void put( Tuple & ) noexcept { } - }; - class - captured_info - { - protected: - captured_info() noexcept - { - } - public: - virtual ~captured_info() noexcept = 0; - virtual void unpack() noexcept = 0; - }; - inline - captured_info:: - ~captured_info() noexcept - { - } - template - class - captured_info_impl: - public captured_info - { - std::tuple...> cap_; - void - unpack() noexcept - { - tuple_put...>>::put(cap_); - } - public: - explicit - captured_info_impl( std::tuple...> && cap ) noexcept: - cap_(std::move(cap)) - { - } - }; - template - optional - slot_extract() noexcept - { - auto & x = tl_slot::tl_instance(); - if( x.has_value() ) - return optional(x.extract_value()); - else - return { }; - } - template - std::tuple...> - extract( expect & ) noexcept - { - return std::make_tuple(slot_extract()...); - } - } - } - } - -#endif diff --git a/include/boost/leaf/detail/optional.hpp b/include/boost/leaf/detail/optional.hpp index d2ddac2..1cf8973 100644 --- a/include/boost/leaf/detail/optional.hpp +++ b/include/boost/leaf/detail/optional.hpp @@ -7,7 +7,6 @@ #ifndef UUID_47258FCCB6B411E8A1F35AA00C39171A #define UUID_47258FCCB6B411E8A1F35AA00C39171A -#include #include #include @@ -27,6 +26,7 @@ boost union { T value_; }; bool has_value_; public: + typedef T value_type; optional() noexcept: has_value_(false) { @@ -80,19 +80,21 @@ boost has_value_=false; } } - void + T & put( T const & v ) { reset(); (void) new(&value_) T(v); has_value_=true; + return value_; } - void + T & put( T && v ) noexcept { reset(); (void) new(&value_) T(std::move(v)); has_value_=true; + return value_; } bool has_value() const noexcept diff --git a/include/boost/leaf/detail/diagnostic_print.hpp b/include/boost/leaf/detail/print.hpp similarity index 81% rename from include/boost/leaf/detail/diagnostic_print.hpp rename to include/boost/leaf/detail/print.hpp index 89a9a6b..fb94a25 100644 --- a/include/boost/leaf/detail/diagnostic_print.hpp +++ b/include/boost/leaf/detail/print.hpp @@ -28,8 +28,19 @@ boost namespace leaf_detail { - template struct is_printable { static constexpr bool value=false; }; - template struct is_printable()<(), void())> { static constexpr bool value=true; }; + template + struct + is_printable + { + static constexpr bool value=false; + }; + template + struct + is_printable()<(), void())> + { + static constexpr bool value=true; + }; + //////////////////////////////////////// template ::value,bool ValuePrintable=is_printable::value> struct diagnostic; template diff --git a/include/boost/leaf/detail/tl_slot.hpp b/include/boost/leaf/detail/tl_slot.hpp deleted file mode 100644 index 53756ee..0000000 --- a/include/boost/leaf/detail/tl_slot.hpp +++ /dev/null @@ -1,198 +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_BF995DE0B2DF11E8B0E10DFDAD35F1A2 -#define UUID_BF995DE0B2DF11E8B0E10DFDAD35F1A2 - -#include -#include -#include - -namespace -boost - { - namespace - leaf - { - struct in_function; - struct in_file; - struct at_line; - template struct ei_source_location { char const * value; }; - template <> struct ei_source_location { int value; }; - namespace - leaf_detail - { - inline - bool & - current_error_flag() noexcept - { - static thread_local bool f=false; - return f; - } - inline - unsigned & - current_seq_id() noexcept - { - static thread_local unsigned n=0; - return n; - } - class - tl_slot_base - { - int open_count_; - public: - virtual void reset() noexcept = 0; - protected: - tl_slot_base() noexcept: - open_count_(0) - { - } - ~tl_slot_base() noexcept - { - } - public: - static - unsigned - bump_current_seq_id() - { - return ++current_seq_id(); - } - int - open() noexcept - { - assert(open_count_>=0); - return ++open_count_; - } - int - close() noexcept - { - assert(is_open()); - if( --open_count_==0 ) - reset(); - return open_count_; - } - int - is_open() const noexcept - { - assert(open_count_>=0); - return open_count_; - } - }; - template - class - tl_slot: - optional, - public tl_slot_base - { - tl_slot( tl_slot const & ) = delete; - tl_slot & operator=( tl_slot const & ) = delete; - typedef optional base; - unsigned seq_id_; - tl_slot() noexcept: - seq_id_(0) - { - } - ~tl_slot() noexcept - { - } - public: - bool - has_value() const noexcept - { - if( base::has_value() ) - { - assert(is_open()); - return seq_id_==current_seq_id(); - } - else - return false; - } - T const & - value() const noexcept - { - assert(has_value()); - return base::value(); - } - T & - value() noexcept - { - assert(has_value()); - return base::value(); - } - T - extract_value() noexcept - { - assert(has_value()); - return base::extract_value(); - } - bool - put( T const & x ) - { - if( is_open() ) - { - base::put(x); - seq_id_ = current_seq_id(); - return true; - } - else - return false; - } - bool - put( T && x ) noexcept - { - if( is_open() ) - { - base::put(std::move(x)); - seq_id_ = current_seq_id(); - return true; - } - else - return false; - } - void - reset() noexcept - { - base::reset(); - } - bool - diagnostic_print( std::ostream & os ) const - { - if( has_value() ) - return diagnostic::print(os,value()); - else - return false; - } - static - tl_slot & - tl_instance() noexcept - { - static_assert(sizeof(T::value),"Error info types must define a data member value"); - static thread_local tl_slot x; - return x; - } - }; - template - struct - diagnostic,false,true> - { - static - bool - print( std::ostream &, ei_source_location const & ) - { - return false; - } - }; - } - inline - bool - has_current_error() noexcept - { - return leaf_detail::current_error_flag() || std::uncaught_exception(); - } - } - } - -#endif diff --git a/include/boost/leaf/detail/tuple.hpp b/include/boost/leaf/detail/tuple.hpp new file mode 100644 index 0000000..c79b445 --- /dev/null +++ b/include/boost/leaf/detail/tuple.hpp @@ -0,0 +1,47 @@ +//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_171F6820D42311E89C0E377FC92C3C47 +#define UUID_171F6820D42311E89C0E377FC92C3C47 + +#include + +namespace +boost + { + namespace + leaf + { + namespace + leaf_detail + { + template + struct type_index; + template + struct + type_index + { + static const int value = 0; + }; + template + struct + type_index + { + static const int value = 1 + type_index::value; + }; + template + struct tuple_type_index; + template + struct + tuple_type_index> + { + static const int value = type_index::value; + }; + } + } + } + +#endif diff --git a/include/boost/leaf/diagnostic_information.hpp b/include/boost/leaf/diagnostic_information.hpp deleted file mode 100644 index 5951b89..0000000 --- a/include/boost/leaf/diagnostic_information.hpp +++ /dev/null @@ -1,114 +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_E4B56A60B87011E890CB55B30D39171A -#define UUID_E4B56A60B87011E890CB55B30D39171A - -#include -#include - -namespace -boost - { - namespace - leaf - { - namespace - leaf_detail - { - template - int - slot_print( std::ostream & os ) - { - if( tl_slot::tl_instance().diagnostic_print(os) ) - os << std::endl; - return 42; - } - inline - char const * - get_info_function() - { - auto & info = tl_slot>::tl_instance(); - if( info.has_value() ) - return info.value().value; - else - return 0; - } - inline - char const * - get_info_file() - { - auto & info = tl_slot>::tl_instance(); - if( info.has_value() ) - return info.value().value; - else - return 0; - } - inline - int - get_info_line() - { - auto & info = tl_slot>::tl_instance(); - if( info.has_value() ) - return info.value().value; - else - return -1; - } -#ifdef _MSC_VER - template - struct - msvc_workaround_print - { - static - void - print( std::ostream & os ) - { - typedef typename std::tuple_element::type ith_type; - (void) slot_print(os); - msvc_workaround_print::print(os); - } - }; - template - struct - msvc_workaround_print<0,Tuple> - { - static void print( std::ostream & ) { } - }; - template - void - slots_print( std::ostream & os ) noexcept - { - msvc_workaround_print>::print(os); - } -#else - template - void - slots_print( std::ostream & os ) - { - { using _ = int[ ]; (void) _ { 42, slot_print(os)... }; }; - } -#endif - } - template - void - expect:: - print_diagnostic_information( std::ostream & os ) const - { - using namespace leaf_detail; - slots_print(os); - int line = get_info_line(); - if( char const * file = get_info_file() ) - if( line==-1 ) - os << "In " << file << std::endl; - else - os << "At " << file << '(' << line << ')' << std::endl; - if( char const * function = get_info_function() ) - os << "In function " << function << std::endl; - } - } - } - -#endif diff --git a/include/boost/leaf/error.hpp b/include/boost/leaf/error.hpp new file mode 100644 index 0000000..d49756f --- /dev/null +++ b/include/boost/leaf/error.hpp @@ -0,0 +1,244 @@ +//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_BA049396D0D411E8B45DF7D4A759E189 +#define UUID_BA049396D0D411E8B45DF7D4A759E189 + +#include +#include +#include +#include +#include + +namespace +boost + { + namespace + leaf + { + class error; + namespace + leaf_detail + { + template + T * put1( T && v, error const & e ) noexcept; + error const & set_current_error( error const & ); + struct current_error_state; + } + //////////////////////////////////////// + class + error + { + friend struct leaf_detail::current_error_state; + + unsigned id_; + + struct default_ { }; + explicit + error( default_ ) noexcept: + id_(-1) + { + } + static + unsigned + new_id() noexcept + { + static std::atomic x; + return ++x; + } + public: + error() noexcept: + id_(new_id()) + { + (void) leaf_detail::set_current_error(*this); + } + template + explicit + error( T && ... v ) noexcept: + id_(new_id()) + { + (void) leaf_detail::set_current_error(propagate(std::forward(v)...)); + } + template + error + propagate( T && ... v ) const noexcept + { + { using _ = void const * [ ]; (void) _ { leaf_detail::put1(std::forward(v),*this)... }; } + return *this; + } + friend + bool + operator==( error const & e1, error const & e2 ) noexcept + { + return e1.id_==e2.id_; + } + friend + bool + operator!=( error const & e1, error const & e2 ) noexcept + { + return e1.id_!=e2.id_; + } + friend + std::ostream & + operator<<( std::ostream & os, error const & e ) + { + char buf[sizeof(e.id_)*CHAR_BIT/4+1]; + int nw = std::sprintf(buf,"%X",e.id_); + assert(nw>=0); + assert(nw + struct + error_info + { + T v; + error e; + }; + template + class + slot: + public optional> + { + slot( slot const & ) = delete; + slot & operator=( slot const & ) = delete; + typedef optional> base; + slot * prev_; + public: + typedef decltype(T::value) value_type; + slot() noexcept; + ~slot() noexcept; + }; + template + slot * & + tl_slot_ptr() + { + static thread_local slot * s; + return s; + } + template + slot:: + slot() noexcept + { + slot * & p = tl_slot_ptr(); + prev_ = p; + p = this; + } + template + slot:: + ~slot() noexcept + { + if( prev_ && this->has_value() ) + if( auto ce = current_error() ) + if( *ce==this->value().e ) + (void) prev_->put(this->extract_value()); + tl_slot_ptr() = prev_; + } + template + T * + put1( 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; + else + return 0; + } + } + //////////////////////////////////////// + template + error + propagate( E && ... e ) noexcept + { + if( error const * ce = current_error() ) + return ce->propagate(std::forward(e)...); + else + return error(std::forward(e)...); + } + //////////////////////////////////////// + namespace + leaf_detail + { + template + struct + match_impl + { + F f; + }; + } + template + leaf_detail::match_impl + match( F && f ) + { + return leaf_detail::match_impl { std::move(f) }; + } + } + } + +#endif diff --git a/include/boost/leaf/error_capture.hpp b/include/boost/leaf/error_capture.hpp new file mode 100644 index 0000000..c1e5539 --- /dev/null +++ b/include/boost/leaf/error_capture.hpp @@ -0,0 +1,302 @@ +//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_C86E4C4ED0F011E8BB777EB8A659E189 +#define UUID_C86E4C4ED0F011E8BB777EB8A659E189 + +#include +#include +#include +#include + +namespace +boost + { + namespace + leaf + { + class error_capture; + + template + decltype(P::value) const * peek( error_capture const & ); + //////////////////////////////////////// + namespace + leaf_detail + { + template + struct + tuple_dynamic_bind + { + static + void const * + bind( Tuple const & tup, char const * (*type_id)() ) noexcept + { + assert(type_id!=0); + typedef typename std::tuple_element::type ith_type; + if( &type == type_id ) + return &std::get(tup); + return tuple_dynamic_bind::bind(tup,type_id); + } + }; + template + struct + tuple_dynamic_bind<0,Tuple> + { + static void const * bind( Tuple const &, char const * (*)() ) noexcept { return 0; } + }; + //////////////////////////////////////// + template + struct all_available; + template + struct + all_available + { + static + bool + check( error_capture const & cap ) noexcept + { + return peek(cap) && all_available::check(cap); + } + }; + template <> + struct + all_available<> + { + static bool check( error_capture const & ) noexcept { return true; } + }; + //////////////////////////////////////// + template + struct + tuple_print + { + static + void + print( std::ostream & os, Tuple const & tup ) + { + typedef typename std::tuple_element::type ith_type; + tuple_print::print(os,tup); + auto & opt = std::get(tup); + if( opt.has_value() && diagnostic::print(os,opt.value()) ) + os << std::endl; + } + }; + template + struct + tuple_print<0,Tuple> + { + static void print( std::ostream &, Tuple const & ) { } + }; + //////////////////////////////////////// + template + struct + tuple_propagate + { + static + void + propagate( error const & e, Tuple & tup ) noexcept + { + tuple_propagate::propagate(e,tup); + auto & opt = std::get(tup); + if( opt.has_value() ) + e.propagate(opt.extract_value()); + } + }; + template + struct + tuple_propagate<0,Tuple> + { + static void propagate( error const &, Tuple & ) noexcept { } + }; + } + //////////////////////////////////////// + class + error_capture + { + template + friend decltype(P::value) const * leaf::peek( error_capture const & ); + + class + dynamic_store + { + mutable std::atomic refcount_; + virtual void const * bind_( char const * (*)() ) const noexcept = 0; + protected: + dynamic_store() noexcept: + refcount_(0) + { + } + public: + virtual + ~dynamic_store() noexcept + { + } + void + addref() const noexcept + { + ++refcount_; + } + void + release() const noexcept + { + if( !--refcount_ ) + delete this; + } + template + leaf_detail::optional const * + bind() const noexcept + { + if( void const * p = bind_(&type) ) + return static_cast const *>(p); + else + return 0; + } + virtual void diagnostic_print( std::ostream & ) const = 0; + virtual void propagate( error const & ) noexcept = 0; + }; + template + class + dynamic_store_impl: + public dynamic_store + { + std::tuple...> s_; + public: + explicit + dynamic_store_impl( std::tuple...> && s ) noexcept: + s_(std::move(s)) + { + } + void const * + bind_( char const * (*type_id)() ) const noexcept + { + using namespace leaf_detail; + assert(type_id!=0); + return tuple_dynamic_bind...>>::bind(s_,type_id); + } + void + diagnostic_print( std::ostream & os ) const + { + leaf_detail::tuple_print::print(os,s_); + } + void + propagate( error const & e ) noexcept + { + leaf_detail::tuple_propagate::propagate(e,s_); + } + }; + void + free() noexcept + { + if( s_ ) + { + s_->release(); + s_=0; + } + } + template + int + unwrap( leaf_detail::match_impl const & m, bool & matched ) const noexcept + { + if( !matched && (matched=leaf_detail::all_available::check(*this)) ) + (void) m.f( *peek(*this)... ); + return 42; + } + error e_; + dynamic_store * s_; + public: + error_capture() noexcept: + s_(0) + { + } + template + error_capture( error const & e, std::tuple...> && s ) noexcept: + e_(e), + s_(new dynamic_store_impl(std::move(s))) + { + s_->addref(); + } + ~error_capture() noexcept + { + free(); + } + error_capture( error_capture const & x ) noexcept: + e_(x.e_), + s_(x.s_) + { + if( s_ ) + s_->addref(); + } + error_capture( error_capture && x ) noexcept: + e_(std::move(x.e_)), + s_(x.s_) + { + x.s_ = 0; + } + error_capture & + operator=( error_capture const & x ) noexcept + { + e_ = x.e_; + s_ = x.s_; + s_->addref(); + return *this; + } + error_capture & + operator=( error_capture && x ) noexcept + { + e_ = x.e_; + s_ = x.s_; + x.s_ = 0; + return *this; + } + explicit + operator bool() const noexcept + { + return s_!=0; + } + error + propagate() noexcept + { + assert(s_); + s_->propagate(e_); + free(); + return e_; + } + template + friend + void + handle_error( error_capture & e, M && ... m ) + { + if( e ) + { + bool matched = false; + { using _ = int[ ]; (void) _ { 42, e.unwrap(m,matched)... }; } + if( !matched ) + throw_exception(mismatch_error()); + e.free(); + } + } + friend + void + diagnostic_print( std::ostream & os, error_capture const & e ) + { + if( e ) + e.s_->diagnostic_print(os); + } + }; + //////////////////////////////////////// + template + decltype(P::value) const * + peek( error_capture const & e ) + { + if( e ) + if( auto * opt = e.s_->bind

() ) + if( opt->has_value() ) + return &opt->value().value; + return 0; + } + } + } + +#endif diff --git a/include/boost/leaf/exception.hpp b/include/boost/leaf/exception.hpp new file mode 100644 index 0000000..800bc83 --- /dev/null +++ b/include/boost/leaf/exception.hpp @@ -0,0 +1,58 @@ +//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_87F274C4D4BA11E89928D55AC82C3C47 +#define UUID_87F274C4D4BA11E89928D55AC82C3C47 + +#include +#include + +namespace +boost + { + namespace + leaf + { + template + decltype(P::value) const * + peek( expect const & exp, std::exception const & e ) + { + if( auto err = dynamic_cast(&e) ) + return peek

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

(exp,*current_error()); + } + } + template + void + handle_error( expect const & exp, std::exception const & e, M && ... m ) + { + if( auto err = dynamic_cast(&e) ) + handle_error(exp,*err,m...); + else + { + assert(current_error()!=0); + handle_error(exp,*current_error(),m...); + } + } + template + void + diagnostic_print( std::ostream & os, expect const & exp, std::exception const & e ) + { + if( auto err = dynamic_cast(&e) ) + diagnostic_print(os,exp,*err); + else + { + assert(current_error()!=0); + diagnostic_print(os,exp); + } + } + } + } + +#endif diff --git a/include/boost/leaf/exception_capture.hpp b/include/boost/leaf/exception_capture.hpp new file mode 100644 index 0000000..b8a1cfa --- /dev/null +++ b/include/boost/leaf/exception_capture.hpp @@ -0,0 +1,139 @@ +//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_BC24FB98B2DE11E884419CF5AD35F1A2 +#define UUID_BC24FB98B2DE11E884419CF5AD35F1A2 + +#include +#include + +namespace +boost + { + namespace + leaf + { + namespace + leaf_detail + { + class + captured_exception: + public std::exception + { + error_capture cap_; + std::exception_ptr ex_; + public: + captured_exception( error_capture && cap, std::exception_ptr && ex ) noexcept: + cap_(std::move(cap)), + ex_(std::move(ex)) + { + assert(ex_); + } + [[noreturn]] + void + rethrow_original_exception() + { + set_current_error(cap_.propagate()); + std::rethrow_exception(ex_); + } + friend + void + diagnostic_print( std::ostream & os, captured_exception const & ce ) + { + diagnostic_print(os,ce.cap_); + } + }; + template + class + exception_trap + { + F f_; + public: + explicit + exception_trap( F && f ) noexcept: + f_(std::move(f)) + { + } + template + decltype(std::declval()()) + operator()( A && ... a ) + { + expect exp; + try + { + return f_(std::forward(a)...); + } + catch( error const & e ) + { + throw captured_exception(capture(exp,e),std::current_exception()); + } + catch(...) + { + throw captured_exception(capture(exp,*current_error()),std::current_exception()); + } + } + }; + } + template + leaf_detail::exception_trap + capture_exception( F && f ) noexcept + { + return leaf_detail::exception_trap(std::move(f)); + } + template + decltype(std::declval().get()) + get( Future && f ) + { + try + { + return std::forward(f).get(); + } + catch( leaf_detail::captured_exception & ex ) + { + ex.rethrow_original_exception(); + } + } + //////////////////////////////////////// + template + void + current_exception_diagnostic_print( std::ostream & os, expect const & exp ) + { + os << "Current Exception Diagnostic Information:" << std::endl; + try + { + throw; + } + catch( std::exception const & ex ) + { + os << + "Exception dynamic type: " << typeid(ex).name() << std::endl << + "std::exception::what(): " << ex.what() << std::endl; + } + catch( ... ) + { + os << "Unknown exception type (not a std::exception)" << std::endl; + } + try + { + throw; + } + catch( leaf_detail::captured_exception const & e ) + { + diagnostic_print(os,e); + } + catch( error const & e ) + { + diagnostic_print(os,exp,e); + } + catch( ... ) + { + diagnostic_print(os,exp); + } + } + } + } + +#endif diff --git a/include/boost/leaf/expect.hpp b/include/boost/leaf/expect.hpp index bf36f93..35a3c73 100644 --- a/include/boost/leaf/expect.hpp +++ b/include/boost/leaf/expect.hpp @@ -7,8 +7,9 @@ #ifndef UUID_AFBBD676B2FF11E8984C7976AE35F1A2 #define UUID_AFBBD676B2FF11E8984C7976AE35F1A2 -#include -#include +#include +#include +#include namespace boost @@ -16,223 +17,174 @@ boost namespace leaf { - struct mismatch_error: virtual std::exception { }; - - template - class expect; - - template - class result; - - class bad_result: public std::exception { }; - namespace leaf_detail { - template - int - slot_open_reset() - { - auto & info = tl_slot::tl_instance(); - (void) info.open(); - info.reset(); - return 42; - } - template - int - slot_close() - { - tl_slot::tl_instance().close(); - return 42; - } -#ifdef _MSC_VER - template + template + struct all_available_slot; + template struct - msvc_workaround_open_reset - { - static - void - open_reset() noexcept - { - typedef typename std::tuple_element::type ith_type; - (void) slot_open_reset(); - msvc_workaround_open_reset::open_reset(); - } - }; - template - struct - msvc_workaround_open_reset<0,Tuple> - { - static void open_reset() noexcept { } - }; - template - struct - msvc_workaround_close - { - static - void - close() noexcept - { - typedef typename std::tuple_element::type ith_type; - (void) slot_close(); - msvc_workaround_close::close(); - } - }; - template - struct - msvc_workaround_close<0,Tuple> - { - static void close() noexcept { } - }; - template - struct - msvc_workaround_slots_available + all_available_slot { static bool - slots_available() noexcept + check( Tuple const & tup, error const & e ) noexcept { - typedef typename std::tuple_element::type ith_type; - return tl_info::tl_instance().has_value() && msvc_workaround_slots_available::slots_available(); + auto & sl = std::get::value>(tup); + return sl.has_value() && sl.value().e==e && all_available_slot::check(tup,e); } }; template struct - msvc_workaround_slots_available<0,Tuple> + all_available_slot { - static bool slots_available() noexcept { return true; } + static bool check( Tuple const &, error const & ) noexcept { return true; } }; - template - void - slots_open_reset() noexcept + //////////////////////////////////////// + template + struct + tuple_print_slot { - msvc_workaround_open_reset>::open_reset(); - } - template - void - slots_close() noexcept - { - msvc_workaround_close>::close(); - } - template - bool - slots_available() noexcept - { - return msvc_workaround_slots_available>::slots_available(); - } -#else - template - void - slots_open_reset() noexcept - { - { using _ = int[ ]; (void) _ { 42, slot_open_reset()... }; } - } - template - void - slots_close() noexcept - { - { using _ = int[ ]; (void) _ { 42, slot_close()... }; } - } - template - bool - slots_available() noexcept - { - bool const available[ ] = { tl_slot::tl_instance().has_value()... }; - for( auto i : available ) - if( !i ) - return false; - return true; - } -#endif - - template class capture_wrapper; - template - class - match_impl - { - match_impl( match_impl const & ) = delete; - match_impl & operator=( match_impl const & ) = delete; - F f_; - public: - match_impl( match_impl && ) = default; - explicit - match_impl( F && f ) noexcept: - f_(std::move(f)) + static + void + print( std::ostream & os, Tuple const & tup ) { - } - template - int - unwrap( bool & still_has_error, int & count ) const - { - using namespace leaf_detail; - bool const last = (--count==0); - assert(count>=0); - if( still_has_error ) + tuple_print_slot::print(os,tup); + auto & opt = std::get(tup); + if( opt.has_value() ) { - if( !slots_available() ) - if( last ) - throw mismatch_error(); - else - return 42; - (void) f_(tl_slot::tl_instance().value().value...); - still_has_error = false; + auto & x = opt.value(); + if( diagnostic::print(os,x.v) ) + os << "(0x" << x.e << ')' << std::endl; + } + } + static + void + print( std::ostream & os, Tuple const & tup, error const & e ) + { + tuple_print_slot::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; } - return 42; } }; + template + struct + tuple_print_slot<0,Tuple> + { + static void print( std::ostream &, Tuple const & ) { } + static void print( std::ostream &, Tuple const &, error const & ) { } + }; + //////////////////////////////////////// + template + optional + convert_optional( slot && x, error const & e ) noexcept + { + if( x.has_value() && x.value().e==e ) + return optional(std::move(x.extract_value().v)); + else + return optional(); + } } - template + template + class expect; + + template + decltype(P::value) const * peek( expect const &, error const & ) noexcept; + + class error_capture; + + template class expect { + friend class error; + + 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; - template - friend class leaf_detail::match_impl; + std::tuple...> s_; + template + int + unwrap( leaf_detail::match_impl const & m, error const & e, bool & matched ) const noexcept + { + using namespace leaf_detail; + if( !matched && (matched=all_available_slot...>::check(s_,e)) ) + (void) m.f( *leaf::peek(*this,e)... ); + return 42; + } public: expect() noexcept { - using namespace leaf_detail; - tl_slot_base::bump_current_seq_id(); - current_error_flag() = false; - slots_open_reset,ei_source_location,ei_source_location,ExpectErrorInfo...>(); + leaf_detail::clear_current_error(); } ~expect() noexcept { - using namespace leaf_detail; - if( !has_current_error() ) - tl_slot_base::bump_current_seq_id(); - slots_close,ei_source_location,ei_source_location,ExpectErrorInfo...>(); } - void print_diagnostic_information( std::ostream & ) const; - void print_current_exception_diagnostic_information( std::ostream & ) const; + template + friend + void + handle_error( expect const & exp, error const & e, M && ... m ) + { + bool matched = false; + { using _ = int[ ]; (void) _ { 42, exp.unwrap(m,e,matched)... }; } + if( !matched ) + throw_exception(mismatch_error()); + leaf_detail::clear_current_error(e); + } + friend + void + diagnostic_print( std::ostream & os, expect const & exp ) + { + leaf_detail::tuple_print_slot::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); + } + friend + typename dependent_type::error_capture + capture( expect & exp, error const & e ) + { + using namespace leaf_detail; + typename dependent_type::error_capture cap( + e, + std::make_tuple( + convert_optional( + std::move(std::get,decltype(exp.s_)>::value>(exp.s_)),e)...)); + clear_current_error(e); + return cap; + } }; - template - decltype(std::declval().value) const * - peek( expect const &, std::exception const & ) + template + decltype(P::value) const * + peek( expect const & exp, error const & e ) noexcept { - auto & x = leaf_detail::tl_slot::tl_instance(); - if( x.has_value() ) - return &x.value().value; - else - return 0; - } - template - void - handle_error( expect & e, std::exception const &, Match && ... m ) - { - int count = sizeof...(Match); - bool & still_has_error = leaf_detail::current_error_flag(); - still_has_error = true; - { using _ = int[ ]; (void) _ { 42, m.unwrap(still_has_error,count)... }; } - } - template - leaf_detail::match_impl - match( F && f ) noexcept - { - return leaf_detail::match_impl(std::move(f)); + auto & opt = std::get::value>(exp.s_); + if( opt.has_value() ) + { + auto & x = opt.value(); + if( x.e==e ) + return &x.v.value; + } + return 0; } } } diff --git a/include/boost/leaf/put.hpp b/include/boost/leaf/preload.hpp similarity index 52% rename from include/boost/leaf/put.hpp rename to include/boost/leaf/preload.hpp index b7bf644..b598faf 100644 --- a/include/boost/leaf/put.hpp +++ b/include/boost/leaf/preload.hpp @@ -7,15 +7,9 @@ #ifndef UUID_8F1C53BEB39F11E8A1C5B6F3E99C4353 #define UUID_8F1C53BEB39F11E8A1C5B6F3E99C4353 -#include -#include +#include #include -#include - -#define ei_SOURCE_LOCATION\ - ::boost::leaf::ei_source_location<::boost::leaf::in_function> {__FUNCTION__},\ - ::boost::leaf::ei_source_location<::boost::leaf::at_line> {__LINE__},\ - ::boost::leaf::ei_source_location<::boost::leaf::in_file> {__FILE__} +#include namespace boost @@ -23,29 +17,6 @@ boost namespace leaf { - template - void - put( ErrorInfo && ... a ) noexcept - { - { using _ = bool[ ]; (void) _ { leaf_detail::tl_slot::tl_instance().put(std::forward(a))... }; } - } - template - [[noreturn]] - void - throw_exception( Exception const & e, ErrorInfo && ... a ) - { - leaf_detail::tl_slot_base::bump_current_seq_id(); - put(std::forward(a)...); - throw e; - } - template - [[noreturn]] - void - throw_exception( Exception const & e ) - { - leaf_detail::tl_slot_base::bump_current_seq_id(); - throw e; - } namespace leaf_detail { @@ -57,9 +28,9 @@ boost { static void - put_( T && x ) noexcept + propagate_( error const & e, T && x ) noexcept { - put(std::move(x)); + e.propagate(std::move(x)); } }; template @@ -68,29 +39,29 @@ boost { static void - put_( F && x ) noexcept + propagate_( error const & e, F && x ) noexcept { - put(x()); + e.propagate(std::forward(x)()); } }; template struct - put_meta + propagate_meta { static void - put( Tuple && t ) noexcept + propagate( error const & e, Tuple && t ) noexcept { typedef typename std::tuple_element::type ith_type; - defer_dispatch::put_(std::move(std::get(std::move(t)))); - put_meta::put(std::move(t)); + defer_dispatch::propagate_(e,std::move(std::get(std::move(t)))); + propagate_meta::propagate(e,std::move(t)); } }; template struct - put_meta<0,Tuple> + propagate_meta<0,Tuple> { - static void put( Tuple && ) noexcept { } + static void propagate( error const &, Tuple && ) noexcept { } }; template class @@ -99,28 +70,29 @@ boost preloaded( preloaded const & ) = delete; preloaded & operator=( preloaded const & ) = delete; typedef std::tuple::type>::type...> tuple_type; - optional to_put_; + optional to_propagate_; public: template explicit preloaded( U && ... a ): - to_put_(tuple_type(std::forward(a)...)) + to_propagate_(tuple_type(std::forward(a)...)) { } preloaded( preloaded && x ) noexcept: - to_put_(std::move(x.to_put_)) + to_propagate_(std::move(x.to_propagate_)) { - assert(!x.to_put_.has_value()); + assert(!x.to_propagate_.has_value()); } ~preloaded() noexcept { - if( to_put_.has_value() && has_current_error() ) - put_meta::put(to_put_.extract_value()); + if( to_propagate_.has_value() ) + if( error const * e = current_error() ) + propagate_meta::propagate(*e,to_propagate_.extract_value()); } void cancel() noexcept { - to_put_.reset(); + to_propagate_.reset(); } }; } @@ -133,6 +105,4 @@ boost } } -#define LEAF_THROW(e) ::boost::leaf::throw_exception(e,ei_SOURCE_LOCATION) - #endif diff --git a/include/boost/leaf/result.hpp b/include/boost/leaf/result.hpp index 5bf7ebb..e9dba8b 100644 --- a/include/boost/leaf/result.hpp +++ b/include/boost/leaf/result.hpp @@ -7,8 +7,7 @@ #ifndef UUID_2CD8E6B8CA8D11E8BD3B80D66CE5B91B #define UUID_2CD8E6B8CA8D11E8BD3B80D66CE5B91B -#include -#include +#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 @@ -20,54 +19,208 @@ boost namespace leaf { + class bad_result: public std::exception { }; + template - class captured_result; - namespace - leaf_detail - { - struct error_tag { }; - } + class result; + + template + class expect; + + template + decltype(P::value) const * peek( expect const &, result const & ); + //////////////////////////////////////// template class - result: - leaf_detail::optional + result { - typedef leaf_detail::optional base; + template + friend decltype(P::value) const * leaf::peek( expect const &, result const & ); + + union + { + T value_; + error err_; + error_capture cap_; + }; + enum class + variant + { + value, + err, + cap + }; + variant which_; + void + destroy() noexcept + { + switch( which_ ) + { + case variant:: + value: + value_.~T(); + break; + case variant:: + err: + err_.~error(); + break; + default: + assert(which_==variant::cap); + cap_.~error_capture(); + } + which_= (variant)-1; + } + void + copy_from( result const & x ) + { + switch( x.which_ ) + { + case variant:: + value: + (void) new(&value_) T(x.value_); + break; + case variant:: + err: + (void) new(&err_) leaf::error(x.err_); + break; + default: + assert(x.which_==variant::cap); + (void) new(&cap_) error_capture(x.cap_); + }; + which_ = x.which_; + } + void + move_from( result && x ) noexcept + { + switch( x.which_ ) + { + case variant:: + value: + (void) new(&value_) T(std::move(x.value_)); + break; + case variant:: + err: + (void) new(&err_) leaf::error(std::move(x.err_)); + break; + default: + assert(x.which_==variant::cap); + (void) new(&cap_) error_capture(std::move(x.cap_)); + }; + which_ = x.which_; + } + public: - using base::has_value; - result(): - base(T()) + + ~result() + { + destroy(); + } + result( result const & x ) + { + copy_from(x); + } + result( result && x ) noexcept + { + move_from(std::move(x)); + } + result() noexcept: + value_(T()), + which_(variant::value) { } result( T const & v ): - base(v) + value_(v), + which_(variant::value) { } result( T && v ) noexcept: - base(std::move(v)) + value_(std::move(v)), + which_(variant::value) { } - result( leaf_detail::error_tag ) noexcept + result( leaf::error const & e ) noexcept: + err_(e), + which_(variant::err) { } + result( leaf::error_capture const & cap ) noexcept: + cap_(cap), + which_(variant::cap) + { + } + result( leaf::error_capture && cap ) noexcept: + cap_(std::move(cap)), + which_(variant::cap) + { + } + result & + operator=( result const & x ) + { + destroy(); + copy_from(x); + return *this; + } + result & + operator=( result && x ) noexcept + { + destroy(); + move_from(std::move(x)); + return *this; + } + void + reset( T const & v ) + { + destroy(); + (void) new(&value_) T(v); + which_ = variant::value; + } + void + reset( T && v ) noexcept + { + destroy(); + (void) new(&value_) T(std::move(v)); + which_ = variant::value; + } + void + reset( leaf::error const & e ) noexcept + { + destroy(); + (void) new(&err_) leaf::error(e); + which_ = variant::err; + return *this; + } + void + reset( leaf::error_capture const & cap ) noexcept + { + destroy(); + (void) new(&cap_) leaf::error_capture(cap); + which_ = variant::cap; + } + void + reset( leaf::error_capture && cap ) noexcept + { + destroy(); + (void) new(&cap_) leaf::error_capture(std::move(cap)); + which_ = variant::cap; + } explicit operator bool() const noexcept { - return has_value(); + return which_==variant::value; } T const & value() const { - if( has_value() ) - return base::value(); + if( which_==variant::value ) + return value_; else throw bad_result(); } T & value() { - if( has_value() ) - return base::value(); + if( which_==variant::value ) + return value_; else throw bad_result(); } @@ -81,103 +234,131 @@ boost { return value(); } - template - leaf_detail::error_tag - error( ErrorInfo && ... a ) noexcept + template + leaf::error + error( E && ... e ) noexcept { - assert(has_current_error()); - assert(!*this); - put(std::forward(a)...); - return leaf_detail::error_tag(); - } - leaf_detail::error_tag - error() noexcept + assert(which_==variant::err); + return err_.propagate(std::forward(e)...); + } + template + friend + result && + capture( expect & exp, result && r ) { - assert(has_current_error()); - assert(!*this); - return leaf_detail::error_tag(); - } - template - captured_result capture( expect & ); + if( r.which_==variant::err ) + { + auto cap = capture(exp,r.err_); + r.err_.~error(); + (void) new (&r.cap_) error_capture(std::move(cap)); + r.which_ = variant::cap; + } + return std::move(r); + } + template + friend + void + handle_error( expect const & exp, result & r, M && ... m ) + { + assert(!r); + if( r.which_==result::variant::err ) + handle_error(exp,r.err_,m...); + else + { + assert(r.which_==result::variant::cap); + handle_error(r.cap_,m...); + } + } + template + friend + void + diagnostic_print( std::ostream & os, expect const & exp, result const & r ) + { + assert(!r); + if( r.which_==result::variant::err ) + return diagnostic_print(os,exp,r.err_); + else + { + assert(r.which_==result::variant::cap); + return diagnostic_print(os,r.cap_); + } + } }; + //////////////////////////////////////// template <> class - result + result: + result { - bool success_; + template + friend decltype(P::value) const * leaf::peek( expect const &, result const & ); + + typedef result base; + public: - result( result && ) = default; - result( result const & ) = default; - result & operator=( result const & ) = default; - result(): - success_(true) + + ~result() { } - result( leaf_detail::error_tag ) noexcept: - success_(false) + result() noexcept { } - explicit - operator bool() const noexcept + result( leaf::error const & e ) noexcept: + base(e) { - return success_; } - template - leaf_detail::error_tag - error( ErrorInfo && ... a ) const noexcept + result( leaf::error_capture const & cap ) noexcept: + base(cap) { - assert(leaf_detail::current_error_flag()); - assert(!*this); - put(std::forward(a)...); - return leaf_detail::error_tag(); - } - leaf_detail::error_tag - error() const noexcept + } + result( leaf::error_capture && cap ) noexcept: + base(std::move(cap)) { - assert(leaf_detail::current_error_flag()); - assert(!*this); - return leaf_detail::error_tag(); - } - template - captured_result capture( expect & ); + } + using base::operator bool; + using base::error; + using base::reset; + void reset( bool const & ) = delete; + void reset( bool && ) = delete; + template + friend + result && + capture( expect & exp, result && r ) + { + result && rb = std::move(r); + (void) capture(exp,std::move(rb)); + return std::move(r); + } + template + friend + void + handle_error( expect const & exp, result & r, M && ... m ) + { + result & rb = r; + handle_error(exp,rb,m...); + } + template + friend + void + diagnostic_print( std::ostream & os, expect const & exp, result const & r ) + { + result const & rb = r; + diagnostic_print(os,exp,rb); + } }; - template - decltype(std::declval().value) const * - peek( expect const &, result const & r ) + //////////////////////////////////////// + template + decltype(P::value) const * + peek( expect const & exp, result const & r ) { assert(!r); - auto & x = leaf_detail::tl_slot::tl_instance(); - if( x.has_value() ) - return &x.value().value; + if( r.which_==result::variant::err ) + return peek

(exp,r.err_); else - return 0; - } - template - void - handle_error( expect & e, result const & r, Match && ... m ) - { - assert(!r); - int count = sizeof...(Match); - bool & still_has_error = leaf_detail::current_error_flag(); - still_has_error = true; - { using _ = int[ ]; (void) _ { 42, m.unwrap(still_has_error,count)... }; } - } - template - leaf_detail::error_tag - error( ErrorInfo && ... a ) noexcept - { - leaf_detail::current_error_flag() = true; - leaf_detail::tl_slot_base::bump_current_seq_id(); - put(std::forward(a)...); - return leaf_detail::error_tag(); - } - inline - leaf_detail::error_tag - error() noexcept - { - leaf_detail::current_error_flag() = true; - leaf_detail::tl_slot_base::bump_current_seq_id(); - return leaf_detail::error_tag(); + { + assert(r.which_==result::variant::cap); + return peek

(r.cap_); + } } } } diff --git a/include/boost/leaf/throw_exception.hpp b/include/boost/leaf/throw_exception.hpp new file mode 100644 index 0000000..acb50e0 --- /dev/null +++ b/include/boost/leaf/throw_exception.hpp @@ -0,0 +1,71 @@ +//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_0DBBFB5AD3FA11E89F9D20E3C82C3C47 +#define UUID_0DBBFB5AD3FA11E89F9D20E3C82C3C47 + +#include +#include + +#define LEAF_THROW(e) ::boost::leaf::throw_exception(e,LEAF_SOURCE_LOCATION) + +namespace +boost + { + namespace + leaf + { + class + mismatch_error: + public std::exception + { + }; + namespace + leaf_detail + { + inline void enforce_std_exception( std::exception const & ) { } + template + class + exception: + public Ex, + public error + { + exception( exception const & )=delete; + exception & operator=( exception const & )=delete; + bool moved_; + public: + exception( Ex && ex, error && e ): + Ex(std::move(ex)), + error(std::move(e)), + moved_(false) + { + enforce_std_exception(*this); + } + exception( exception && x ) noexcept: + Ex(std::move(x)), + error(std::move(x)), + moved_(false) + { + x.moved_ = true; + } + ~exception() + { + if( !moved_ ) + clear_current_error(*this); + } + }; + } + template + [[noreturn]] + void + throw_exception( Ex && ex, E && ... e ) + { + throw leaf_detail::exception(std::move(ex),error(std::move(e)...)); + } + } + } + +#endif diff --git a/meson.build b/meson.build index 3c6c3bd..c926b7a 100644 --- a/meson.build +++ b/meson.build @@ -23,22 +23,30 @@ includes = [ include_directories('include') ] leaf = declare_dependency( include_directories: includes ) tests = [ - 'optional_test', - 'tl_slot_test', + '_hpp_all_test', + '_hpp_common_test', + '_hpp_error_capture_test', + '_hpp_error_test', + '_hpp_exception_capture_test', + '_hpp_exception_test', + '_hpp_expect_test', + '_hpp_preload_test', + '_hpp_result_test', + '_hpp_throw_exception_test', + 'basic_test', 'diagnostic_print_test', - 'diagnostic_information_test', - 'expect_result_test', - 'expect_eh_test', - 'captured_result_test', - 'captured_result_void_test', - 'capture_exception_test', - 'hpp_capture_exception_test', - 'hpp_captured_result_test', - 'hpp_common_test', - 'hpp_current_exception_diagnostic_information_test', - 'hpp_diagnostic_information_test', - 'hpp_expect_test', - 'hpp_put_test' + 'error_capture_test', + 'error_test', + 'exception_capture_test', + 'exception_test', + 'foreign_exception_test', + 'multiple_errors_test', + 'optional_test', + 'preload_test', + 'print_test', + 'result_capture_test', + 'result_test', + 'result_void_capture_test' ] foreach t : tests test(t, executable(t, 'test/'+t+'.cpp', dependencies: [ leaf ] ) ) diff --git a/test/hpp_put_test.cpp b/test/_hpp_all_test.cpp similarity index 81% rename from test/hpp_put_test.cpp rename to test/_hpp_all_test.cpp index a51fa0d..341dfa8 100644 --- a/test/hpp_put_test.cpp +++ b/test/_hpp_all_test.cpp @@ -4,6 +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 +#include int main() { return 0; } diff --git a/test/hpp_common_test.cpp b/test/_hpp_common_test.cpp similarity index 100% rename from test/hpp_common_test.cpp rename to test/_hpp_common_test.cpp diff --git a/test/hpp_captured_result_test.cpp b/test/_hpp_error_capture_test.cpp similarity index 75% rename from test/hpp_captured_result_test.cpp rename to test/_hpp_error_capture_test.cpp index 19f54ef..cef5ac8 100644 --- a/test/hpp_captured_result_test.cpp +++ b/test/_hpp_error_capture_test.cpp @@ -4,6 +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 +#include int main() { return 0; } diff --git a/test/hpp_transport_test.cpp b/test/_hpp_error_test.cpp similarity index 78% rename from test/hpp_transport_test.cpp rename to test/_hpp_error_test.cpp index 2ded683..ec3c95c 100644 --- a/test/hpp_transport_test.cpp +++ b/test/_hpp_error_test.cpp @@ -4,6 +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 +#include int main() { return 0; } diff --git a/test/hpp_capture_exception_test.cpp b/test/_hpp_exception_capture_test.cpp similarity index 74% rename from test/hpp_capture_exception_test.cpp rename to test/_hpp_exception_capture_test.cpp index 8c9742d..ca42968 100644 --- a/test/hpp_capture_exception_test.cpp +++ b/test/_hpp_exception_capture_test.cpp @@ -4,6 +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 +#include int main() { return 0; } diff --git a/test/hpp_has_current_error_test.cpp b/test/_hpp_exception_test.cpp similarity index 74% rename from test/hpp_has_current_error_test.cpp rename to test/_hpp_exception_test.cpp index f1349ca..10569d6 100644 --- a/test/hpp_has_current_error_test.cpp +++ b/test/_hpp_exception_test.cpp @@ -4,6 +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 +#include int main() { return 0; } diff --git a/test/hpp_expect_test.cpp b/test/_hpp_expect_test.cpp similarity index 100% rename from test/hpp_expect_test.cpp rename to test/_hpp_expect_test.cpp diff --git a/test/_hpp_preload_test.cpp b/test/_hpp_preload_test.cpp new file mode 100644 index 0000000..a865538 --- /dev/null +++ b/test/_hpp_preload_test.cpp @@ -0,0 +1,9 @@ +//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/_hpp_result_test.cpp b/test/_hpp_result_test.cpp new file mode 100644 index 0000000..85cfc16 --- /dev/null +++ b/test/_hpp_result_test.cpp @@ -0,0 +1,9 @@ +//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/_hpp_throw_exception_test.cpp b/test/_hpp_throw_exception_test.cpp new file mode 100644 index 0000000..ed6cc36 --- /dev/null +++ b/test/_hpp_throw_exception_test.cpp @@ -0,0 +1,9 @@ +//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 new file mode 100644 index 0000000..3eeed2b --- /dev/null +++ b/test/basic_test.cpp @@ -0,0 +1,135 @@ +//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 + +namespace leaf = boost::leaf; + +template +struct +info + { + int value; + }; +leaf::error +f1() + { + (void) leaf::propagate(info<4>{4}); + return leaf::error( info<1>{1} ); + } +leaf::error +f2() + { + return f1().propagate( info<2>{2} ); + } +leaf::error +f3() + { + return f2().propagate( info<3>{3} ); + } +leaf::error +f4() + { + return f3().propagate(); + } +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); + } + { + int const * p = leaf::peek>(exp0,e0); + 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(); + { + int const * p = leaf::peek>(exp0,e0); + BOOST_TEST(p && *p==1); + } + { + int const * p = leaf::peek>(exp0,e0); + BOOST_TEST(p && *p==2); + } + BOOST_TEST(!leaf::peek>(exp0,e0)); + 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); + } + { + int const * p = leaf::peek>(exp,e1); + 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)); + } + leaf::error e2 = f4(); + { + int const * p = leaf::peek>(exp,e2); + BOOST_TEST(p && *p==1); + } + { + int const * p = leaf::peek>(exp,e2); + 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, + leaf::match,info<2>,info<4>>( [&c1]( int, int, int ) + { + ++c1; + } ), + leaf::match,info<2>,info<4>>( [&c2]( int, int, int ) + { + ++c2; + } ), + leaf::match,info<1>>( [&c3]( int i2,int i1 ) + { + 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, + 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_information_test.cpp b/test/diagnostic_information_test.cpp deleted file mode 100644 index c0c197f..0000000 --- a/test/diagnostic_information_test.cpp +++ /dev/null @@ -1,110 +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 -#include -#include - -namespace leaf = boost::leaf; - -struct -my_error: - virtual std::exception - { - char const * - what() const noexcept - { - return "my_error"; - } - }; - -struct -printable_payload - { - friend - std::ostream & - operator<<( std::ostream & os, printable_payload const & x ) - { - return os << "printed printable_payload"; - } - }; -struct -non_printable_payload - { - }; -struct -printable_info_printable_payload - { - printable_payload value; - friend - std::ostream & - operator<<( std::ostream & os, printable_info_printable_payload const & x ) - { - return os << "*** printable_info_printable_payload " << x.value << " ***"; - } - }; -struct -printable_info_non_printable_payload - { - non_printable_payload value; - friend - std::ostream & - operator<<( std::ostream & os, printable_info_non_printable_payload const & x ) - { - return os << "*** printable_info_non_printable_payload ***"; - } - }; -struct -non_printable_info_printable_payload - { - printable_payload value; - }; -struct -non_printable_info_non_printable_payload - { - non_printable_payload value; - }; -int -main() - { - leaf::expect - < - printable_info_printable_payload, - printable_info_non_printable_payload, - non_printable_info_printable_payload, - non_printable_info_non_printable_payload, - leaf::ei_errno - > exp; - try - { - leaf::throw_exception( - my_error(), - ei_SOURCE_LOCATION, - printable_info_printable_payload(), - printable_info_non_printable_payload(), - non_printable_info_printable_payload(), - non_printable_info_non_printable_payload(), - leaf::ei_errno{ENOENT} ); - } - catch( - my_error const & e ) - { - handle_error( exp, e, leaf::match<>([ ]{ }) ); - std::ostringstream st; - exp.print_current_exception_diagnostic_information(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); - 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); - std::cout << s; - } - return boost::report_errors(); - } diff --git a/test/diagnostic_print_test.cpp b/test/diagnostic_print_test.cpp index f57b1d4..c4b5bad 100644 --- a/test/diagnostic_print_test.cpp +++ b/test/diagnostic_print_test.cpp @@ -4,90 +4,110 @@ //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 #include #include namespace leaf = boost::leaf; struct -c1 +my_error: + virtual std::exception + { + char const * + what() const noexcept + { + return "my_error"; + } + }; + +struct +printable_payload { - int value; friend std::ostream & - operator<<( std::ostream & os, c1 const & ) + operator<<( std::ostream & os, printable_payload const & x ) { - return os << "c1"; - } + return os << "printed printable_payload"; + } }; struct -c2 +non_printable_payload { - int value; - }; -std::ostream & -operator<<( std::ostream & os, c2 const & ) - { - return os << "c2"; - } -struct -c3 - { - int value; }; struct -c4 +printable_info_printable_payload { - struct unprintable { }; - unprintable value;; + printable_payload value; + friend + std::ostream & + operator<<( std::ostream & os, printable_info_printable_payload const & x ) + { + return os << "*** printable_info_printable_payload " << x.value << " ***"; + } }; -template -bool -check( T const & x, char const * sub ) +struct +printable_info_non_printable_payload { - using namespace leaf::leaf_detail; - std::ostringstream s; - diagnostic::print(s,x); - std::string q = s.str(); - return q.find(sub)!=q.npos; - } + non_printable_payload value; + friend + std::ostream & + operator<<( std::ostream & os, printable_info_non_printable_payload const & x ) + { + return os << "*** printable_info_non_printable_payload ***"; + } + }; +struct +non_printable_info_printable_payload + { + printable_payload value; + }; +struct +non_printable_info_non_printable_payload + { + non_printable_payload value; + }; int main() { - BOOST_TEST(check(c1{42},"c1")); { - c1 x; - c1 & y = x; - BOOST_TEST(check(x,"c1")); - BOOST_TEST(check(y,"c1")); - } - BOOST_TEST(check(c2{42},"c2")); - { - c2 x = {42}; - c2 & y = x; - BOOST_TEST(check(x,"c2")); - BOOST_TEST(check(y,"c2")); - } - BOOST_TEST(check(c3{42},"c3")); - BOOST_TEST(check(c3{42},"42")); - { - c3 x = {42}; - c3 & y = x; - BOOST_TEST(check(x,"c3")); - BOOST_TEST(check(x,"42")); - BOOST_TEST(check(y,"c3")); - BOOST_TEST(check(y,"42")); - } - BOOST_TEST(check(c4(),"c4")); - BOOST_TEST(check(c4(),"N/A")); - { - c4 x; - c4 & y = x; - BOOST_TEST(check(x,"c4")); - BOOST_TEST(check(x,"N/A")); - BOOST_TEST(check(y,"c4")); - BOOST_TEST(check(y,"N/A")); + leaf::expect + < + printable_info_printable_payload, + printable_info_non_printable_payload, + non_printable_info_printable_payload, + non_printable_info_non_printable_payload, + leaf::ei_errno, + leaf::ei_source_location + > exp; + try + { + leaf::throw_exception( + my_error(), + LEAF_SOURCE_LOCATION, + printable_info_printable_payload(), + printable_info_non_printable_payload(), + non_printable_info_printable_payload(), + non_printable_info_non_printable_payload(), + leaf::ei_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(); + 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("*** 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); + std::cout << s; + } } return boost::report_errors(); } diff --git a/test/error_capture_test.cpp b/test/error_capture_test.cpp new file mode 100644 index 0000000..60ff944 --- /dev/null +++ b/test/error_capture_test.cpp @@ -0,0 +1,121 @@ +//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 + +namespace leaf = boost::leaf; + +template +struct +info + { + int value; + }; +leaf::error +f1() + { + return leaf::error( info<1>{1} ); + } +leaf::error +f2() + { + return f1().propagate( info<2>{2} ); + } +leaf::error +f3() + { + return f2().propagate( info<3>{3} ); + } +leaf::error +f4() + { + return f3().propagate(); + } +leaf::error_capture +make_capture() + { + leaf::expect,info<2>,info<4>> exp; + return capture(exp,f4()); + } +int +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); + } + { + int const * p = leaf::peek>(e1); + BOOST_TEST(p && *p==2); + } + BOOST_TEST(!leaf::peek>(e1)); + leaf::expect,info<2>,info<4>> exp; + leaf::error e2 = f4(); + { + int const * p = leaf::peek>(e1); + BOOST_TEST(p && *p==1); + } + { + int const * p = leaf::peek>(e1); + BOOST_TEST(p && *p==2); + } + BOOST_TEST(!leaf::peek>(e1)); + { + int const * p = leaf::peek>(exp,e2); + BOOST_TEST(p && *p==1); + } + { + int const * p = leaf::peek>(exp,e2); + 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, + leaf::match,info<2>,info<4>>( [&c1]( int, int, int ) + { + ++c1; + } ), + leaf::match,info<1>>( [&c2]( int i2,int i1 ) + { + 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, + leaf::match,info<2>,info<3>>( [&c1]( int, int, int ) + { + ++c1; + } ), + leaf::match,info<2>,info<4>>( [&c2]( int, int, int ) + { + ++c2; + } ), + leaf::match,info<1>>( [&c3]( int i2,int i1 ) + { + BOOST_TEST(i1==1); + BOOST_TEST(i2==2); + ++c3; + } ) ); + BOOST_TEST(c1==0); + BOOST_TEST(c2==0); + BOOST_TEST(c3==1); + } + BOOST_TEST(!e1); + return boost::report_errors(); + } diff --git a/test/error_test.cpp b/test/error_test.cpp new file mode 100644 index 0000000..78c66ce --- /dev/null +++ b/test/error_test.cpp @@ -0,0 +1,77 @@ +//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 + +namespace leaf = boost::leaf; + +template +struct +info + { + int value; + }; +leaf::error +f1() + { + return leaf::error( info<1>{1} ); + } +leaf::error +f2() + { + leaf::expect> exp; + leaf::error e=f1(); + BOOST_TEST(*leaf::current_error()==e); + return e.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} ); + } +leaf::error +f4() + { + leaf::expect,info<2>,info<3>,info<4>> exp; + leaf::error e=f3(); + BOOST_TEST(*leaf::current_error()==e); + 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()); + return leaf::error(); + } +int +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)); + 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/capture_exception_test.cpp b/test/exception_capture_test.cpp similarity index 73% rename from test/capture_exception_test.cpp rename to test/exception_capture_test.cpp index 1ae56c4..377a66b 100644 --- a/test/capture_exception_test.cpp +++ b/test/exception_capture_test.cpp @@ -4,7 +4,9 @@ //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 #include #include #include @@ -13,7 +15,8 @@ namespace leaf = boost::leaf; -struct error: std::exception { }; +struct my_error: std::exception { }; + template struct my_info { int value; }; struct @@ -35,15 +38,17 @@ main() { int const a = rand(); int const b = rand(); - int const result = (rand()%10) - 5; - return fut_info { a, b, result, std::async( std::launch::async, - leaf::capture_exception,my_info<2>,my_info<3>>( [a,b,result] + int const res = (rand()%10) - 5; + return fut_info { a, b, res, std::async( std::launch::async, + leaf::capture_exception,my_info<2>,my_info<3>>( [a,b,res] { - auto put = leaf::preload( my_info<1>{a}, my_info<2>{b} ); - if( result>=0 ) - return result; + if( res>=0 ) + return res; else - leaf::throw_exception(error(),my_info<3>{}); + { + auto propagate = leaf::preload( my_info<1>{a},my_info<2>{b},my_info<3>{} ); + throw my_error(); + } } ) ) }; } ); } @@ -59,7 +64,7 @@ main() BOOST_TEST(r==f.result); } catch( - error const & e ) + my_error const & e ) { handle_error( exp, e, leaf::match,my_info<2>>( [&f]( int x1, int x2 ) { diff --git a/test/exception_test.cpp b/test/exception_test.cpp new file mode 100644 index 0000000..65e2d50 --- /dev/null +++ b/test/exception_test.cpp @@ -0,0 +1,104 @@ +//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 { }; + +template +struct +info + { + int value; + }; +void +f1() + { + return leaf::throw_exception( my_error(), info<1>{1} ); + } +void +f2() + { + leaf::expect> exp; + try + { + f1(); + BOOST_TEST(false); + } + catch( leaf::error const & e ) + { + BOOST_TEST(e==*leaf::current_error()); + e.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()==*dynamic_cast(&e)); + 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()); + } + leaf::throw_exception( 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()==*dynamic_cast(&e)); + 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/expect_eh_test.cpp b/test/expect_eh_test.cpp deleted file mode 100644 index 29f1841..0000000 --- a/test/expect_eh_test.cpp +++ /dev/null @@ -1,121 +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 - -namespace leaf = boost::leaf; - -struct error: std::exception { }; - -int & -total_count() - { - static thread_local int c=0; - return c; - } -template -int & -count() - { - static thread_local int c=0; - return c; - } -template -struct -my_info - { - my_info( my_info const & ) = delete; - my_info & operator=( my_info const & ) = delete; - public: - int value; - explicit - my_info( int value ): - value(value) - { - ++total_count(); - ++count(); - } - my_info( my_info && x ): - value(x.value) - { - ++total_count(); - ++count(); - } - ~my_info() - { - --total_count(); - --count(); - } - }; -int -main() - { - using namespace leaf::leaf_detail; - /////////////////////////////////////////////// - { - leaf::expect,my_info<3>> exp; - try - { - auto put = leaf::preload( my_info<2>(42), my_info<3>(43) ); - leaf::throw_exception(error()); - } - catch( - error const & e ) - { - BOOST_TEST((!leaf::peek>(exp,e))); - BOOST_TEST((leaf::peek>(exp,e) && *leaf::peek>(exp,e)==42)); - BOOST_TEST((leaf::peek>(exp,e) && *leaf::peek>(exp,e)==43)); - bool called = false; - handle_error( exp, e, leaf::match,my_info<2>>( [&called]( int x3, int x2 ) - { - called = true; - BOOST_TEST(x2==42); - BOOST_TEST(x3==43); - } ) ); - BOOST_TEST(called); - } - } - BOOST_TEST(total_count()==0); - /////////////////////////////////////////////// - { - leaf::expect,my_info<3>> exp; - try - { - leaf::expect,my_info<2>> exp; - try - { - auto put = leaf::preload(my_info<2>(42)); - leaf::throw_exception(error()); - } - catch( - error const & e ) - { - BOOST_TEST((!leaf::peek>(exp,e))); - BOOST_TEST((leaf::peek>(exp,e) && *leaf::peek>(exp,e)==42)); - BOOST_TEST((!leaf::peek>(exp,e))); - throw; - } - } - catch( - error const & e ) - { - BOOST_TEST((!leaf::peek>(exp,e))); - BOOST_TEST((leaf::peek>(exp,e) && *leaf::peek>(exp,e)==42)); - BOOST_TEST((!leaf::peek>(exp,e))); - bool called = false; - handle_error( exp, e, leaf::match>( [&called]( int x2 ) - { - called = true; - BOOST_TEST(x2==42); - } ) ); - BOOST_TEST(called); - } - } - BOOST_TEST(total_count()==0); - return boost::report_errors(); - } diff --git a/test/expect_result_test.cpp b/test/expect_result_test.cpp deleted file mode 100644 index 8e017ce..0000000 --- a/test/expect_result_test.cpp +++ /dev/null @@ -1,120 +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 - -namespace leaf = boost::leaf; - -int & -total_count() - { - static thread_local int c=0; - return c; - } -template -int & -count() - { - static thread_local int c=0; - return c; - } -template -struct -my_info - { - my_info( my_info const & ) = delete; - my_info & operator=( my_info const & ) = delete; - public: - int value; - explicit - my_info( int value ): - value(value) - { - ++total_count(); - ++count(); - } - my_info( my_info && x ): - value(x.value) - { - ++total_count(); - ++count(); - } - ~my_info() - { - --total_count(); - --count(); - } - }; -int -main() - { - using namespace leaf::leaf_detail; - /////////////////////////////////////////////// - { - leaf::expect,my_info<3>> exp; - BOOST_TEST(!leaf::leaf_detail::current_error_flag()); - leaf::result r = [ ] - { - auto put = leaf::preload( my_info<2>(42), my_info<3>(43) ); - return leaf::error(); - }(); - BOOST_TEST(!r); - BOOST_TEST(leaf::leaf_detail::current_error_flag()); - BOOST_TEST((!leaf::peek>(exp,r))); - BOOST_TEST((leaf::peek>(exp,r) && *leaf::peek>(exp,r)==42)); - BOOST_TEST((leaf::peek>(exp,r) && *leaf::peek>(exp,r)==43)); - bool called = false; - handle_error( exp, r, leaf::match,my_info<2>>( [&called]( int x3, int x2 ) - { - called = true; - BOOST_TEST(leaf::leaf_detail::current_error_flag()); - BOOST_TEST(x2==42); - BOOST_TEST(x3==43); - } ) ); - BOOST_TEST(called); - BOOST_TEST(!leaf::leaf_detail::current_error_flag()); - } - BOOST_TEST(total_count()==0); - /////////////////////////////////////////////// - { - leaf::expect,my_info<3>> exp; - BOOST_TEST(!leaf::leaf_detail::current_error_flag()); - leaf::result r = [ ] - { - leaf::expect,my_info<2>> exp; - BOOST_TEST(!leaf::leaf_detail::current_error_flag()); - leaf::result r = [ ] - { - auto put = leaf::preload(my_info<2>(42)); - return leaf::error(); - }(); - BOOST_TEST(!r); - BOOST_TEST(leaf::leaf_detail::current_error_flag()); - BOOST_TEST((!leaf::peek>(exp,r))); - BOOST_TEST((leaf::peek>(exp,r) && *leaf::peek>(exp,r)==42)); - BOOST_TEST((!leaf::peek>(exp,r))); - return r.error(); - }(); - BOOST_TEST(!r); - BOOST_TEST(leaf::leaf_detail::current_error_flag()); - BOOST_TEST((!leaf::peek>(exp,r))); - BOOST_TEST((leaf::peek>(exp,r) && *leaf::peek>(exp,r)==42)); - BOOST_TEST((!leaf::peek>(exp,r))); - bool called = false; - handle_error( exp, r, leaf::match>( [&called]( int x2 ) - { - called = true; - BOOST_TEST(leaf::leaf_detail::current_error_flag()); - BOOST_TEST(x2==42); - } ) ); - BOOST_TEST(called); - BOOST_TEST(!leaf::leaf_detail::current_error_flag()); - } - BOOST_TEST(total_count()==0); - return boost::report_errors(); - } diff --git a/test/foreign_exception_test.cpp b/test/foreign_exception_test.cpp new file mode 100644 index 0000000..29c6eed --- /dev/null +++ b/test/foreign_exception_test.cpp @@ -0,0 +1,109 @@ +//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/hpp_current_exception_diagnostic_information_test.cpp b/test/hpp_current_exception_diagnostic_information_test.cpp deleted file mode 100644 index d9dc19e..0000000 --- a/test/hpp_current_exception_diagnostic_information_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/hpp_diagnostic_information_test.cpp b/test/hpp_diagnostic_information_test.cpp deleted file mode 100644 index 0e56150..0000000 --- a/test/hpp_diagnostic_information_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/multiple_errors_test.cpp b/test/multiple_errors_test.cpp new file mode 100644 index 0000000..4f95176 --- /dev/null +++ b/test/multiple_errors_test.cpp @@ -0,0 +1,63 @@ +//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 + +namespace leaf = boost::leaf; + +template +struct +info + { + int value; + }; +leaf::error +f12() + { + return leaf::error( info<1>{1}, info<2>{2} ); + } +leaf::error +f34() + { + return leaf::error( info<3>{3}, info<4>{4} ); + } +int +main() + { + leaf::expect,info<2>,info<3>,info<4>> exp; + leaf::error e1=f12(); + leaf::error e2=f34(); + int e1c1=0, e1c2=0; + handle_error( exp, e1, + leaf::match,info<4>>( [&e1c1]( int, int ) + { + ++e1c1; + } ), + leaf::match,info<2>>( [&e1c2]( int i1, int i2 ) + { + 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, + leaf::match,info<2>>( [&e2c1]( int, int ) + { + ++e2c1; + } ), + leaf::match,info<4>>( [&e2c2]( int i3, int i4 ) + { + 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/preload_test.cpp b/test/preload_test.cpp new file mode 100644 index 0000000..d09ab98 --- /dev/null +++ b/test/preload_test.cpp @@ -0,0 +1,65 @@ +//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 + +namespace leaf = boost::leaf; + +int global; + +int +get_global() noexcept + { + return global; + } +template +struct +info + { + int value; + }; +void +f0() + { + auto propagate = leaf::preload( info<0>{0} ); + } +leaf::error +f1() + { + f0(); + global = 0; + auto propagate = leaf::preload( info<1>{1}, [ ] { return info<42>{get_global()}; } ); + global = 42; + return leaf::error( info<2>{2} ); + } +leaf::error +f2() + { + auto propagate = leaf::preload( info<3>{3} ); + propagate.cancel(); + return f1().propagate( info<4>{4} ); + } +int +main() + { + leaf::expect,info<1>,info<2>,info<3>,info<4>,info<42>> exp; + leaf::error e = f2(); + BOOST_TEST(!leaf::peek>(exp,e)); + int c=0; + 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); + BOOST_TEST(i1==1); + BOOST_TEST(i2==2); + BOOST_TEST(i4==4); + ++c; + } ) ); + BOOST_TEST(c==1); + return boost::report_errors(); + } diff --git a/test/print_test.cpp b/test/print_test.cpp new file mode 100644 index 0000000..08a1d2e --- /dev/null +++ b/test/print_test.cpp @@ -0,0 +1,93 @@ +//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 + +namespace leaf = boost::leaf; + +struct +c1 + { + int value; + friend + std::ostream & + operator<<( std::ostream & os, c1 const & ) + { + return os << "c1"; + } + }; +struct +c2 + { + int value; + }; +std::ostream & +operator<<( std::ostream & os, c2 const & ) + { + return os << "c2"; + } +struct +c3 + { + int value; + }; +struct +c4 + { + struct unprintable { }; + unprintable value;; + }; +template +bool +check( T const & x, char const * sub ) + { + using namespace leaf::leaf_detail; + std::ostringstream s; + diagnostic::print(s,x); + std::string q = s.str(); + return q.find(sub)!=q.npos; + } +int +main() + { + BOOST_TEST(check(c1{42},"c1")); + { + c1 x; + c1 & y = x; + BOOST_TEST(check(x,"c1")); + BOOST_TEST(check(y,"c1")); + } + BOOST_TEST(check(c2{42},"c2")); + { + c2 x = {42}; + c2 & y = x; + BOOST_TEST(check(x,"c2")); + BOOST_TEST(check(y,"c2")); + } + BOOST_TEST(check(c3{42},"c3")); + BOOST_TEST(check(c3{42},"42")); + { + c3 x = {42}; + c3 & y = x; + BOOST_TEST(check(x,"c3")); + BOOST_TEST(check(x,"42")); + BOOST_TEST(check(y,"c3")); + BOOST_TEST(check(y,"42")); + } + BOOST_TEST(check(c4(),"c4")); + BOOST_TEST(check(c4(),"N/A")); + { + c4 x; + c4 & y = x; + BOOST_TEST(check(x,"c4")); + BOOST_TEST(check(x,"N/A")); + BOOST_TEST(check(y,"c4")); + BOOST_TEST(check(y,"N/A")); + } + return boost::report_errors(); + } diff --git a/test/captured_result_test.cpp b/test/result_capture_test.cpp similarity index 73% rename from test/captured_result_test.cpp rename to test/result_capture_test.cpp index 2b82f8c..3029e61 100644 --- a/test/captured_result_test.cpp +++ b/test/result_capture_test.cpp @@ -4,7 +4,8 @@ //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 #include #include @@ -21,7 +22,7 @@ fut_info int a; int b; int result; - std::future> fut; + std::future> fut; }; int @@ -34,14 +35,14 @@ main() { int const a = rand(); int const b = rand(); - int const result = (rand()%10) - 5; - return fut_info { a, b, result, std::async( std::launch::async, [a,b,result] + int const res = (rand()%10) - 5; + return fut_info { a, b, res, std::async( std::launch::async, [a,b,res] { leaf::expect,my_info<2>,my_info<3>> exp; - if( result>=0 ) - return leaf::result(result).capture(exp); + if( res>=0 ) + return capture(exp,leaf::result(res)); else - return leaf::result(leaf::error(my_info<1>{a},my_info<2>{b},my_info<3>{})).capture(exp); + return capture(exp,leaf::result(leaf::error(my_info<1>{a},my_info<2>{b},my_info<3>{}))); } ) }; } ); } @@ -50,7 +51,7 @@ main() using namespace leaf::leaf_detail; f.fut.wait(); leaf::expect,my_info<2>,my_info<4>> exp; - if( leaf::result r = f.fut.get().get() ) + if( leaf::result r = f.fut.get() ) { BOOST_TEST(*r>=0); BOOST_TEST(*r==f.result); diff --git a/test/result_test.cpp b/test/result_test.cpp new file mode 100644 index 0000000..f495b6a --- /dev/null +++ b/test/result_test.cpp @@ -0,0 +1,96 @@ +//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_value + { + }; +template +struct +info + { + int value; + }; +leaf::result +f1( bool success ) + { + if( success ) + return { }; + else + return leaf::error( info<1>{1} ); + } +leaf::result +f2( bool success ) + { + leaf::expect> exp; + 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} ); + return f2(success); + } +leaf::result +f4( bool success ) + { + leaf::expect,info<2>,info<3>,info<4>> exp; + if( leaf::result r = f3( success ) ) + return r; + else + { + BOOST_TEST(*leaf::current_error()==r.error()); + int c1=0, c2=0; + handle_error( exp, r, + 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()); + return leaf::error(); + } + } +int +main() + { + leaf::expect,info<3>,info<4>> exp; + BOOST_TEST(f4(true)); + 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)); + 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/captured_result_void_test.cpp b/test/result_void_capture_test.cpp similarity index 73% rename from test/captured_result_void_test.cpp rename to test/result_void_capture_test.cpp index 7ec0332..e3983a3 100644 --- a/test/captured_result_void_test.cpp +++ b/test/result_void_capture_test.cpp @@ -4,7 +4,8 @@ //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 #include #include @@ -20,7 +21,7 @@ fut_info { int a; int b; - std::future> fut; + std::future> fut; }; int @@ -33,13 +34,14 @@ main() { int const a = rand(); int const b = rand(); - return fut_info { a, b, std::async( std::launch::async, [a,b] + bool const err = rand()%2; + return fut_info { a, b, std::async( std::launch::async, [a,b,err] { leaf::expect,my_info<2>,my_info<3>> exp; - if( rand()%2 ) - return leaf::result().capture(exp); + if( err ) + return capture(exp,leaf::result()); else - return leaf::result(leaf::error(my_info<1>{a},my_info<2>{b},my_info<3>{})).capture(exp); + return capture(exp,leaf::result(leaf::error(my_info<1>{a},my_info<2>{b},my_info<3>{}))); } ) }; } ); } @@ -48,7 +50,7 @@ main() using namespace leaf::leaf_detail; f.fut.wait(); leaf::expect,my_info<2>,my_info<4>> exp; - if( leaf::result r = f.fut.get().get() ) + if( leaf::result r = f.fut.get() ) { } else diff --git a/test/tl_slot_test.cpp b/test/tl_slot_test.cpp deleted file mode 100644 index 3d11998..0000000 --- a/test/tl_slot_test.cpp +++ /dev/null @@ -1,259 +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 -#include -#include - -namespace leaf = boost::leaf; - -struct error { }; - -template -int & -count() - { - static thread_local int c=0; - return c; - } - -template -class -my_info - { - my_info & operator=( my_info const & ) = delete; - public: - int value; - explicit - my_info( int value ): - value(value) - { - BOOST_TEST(++count()>0); - } - my_info( my_info const & x ): - value(x.value) - { - BOOST_TEST(++count()>0); - } - my_info( my_info && x ): - value(x.value) - { - x.value=-1; - BOOST_TEST(++count()>0); - } - ~my_info() - { - BOOST_TEST(--count()>=0); - } - }; - -class -throws_on_copy - { - throws_on_copy & operator=( throws_on_copy const & )=delete; - public: - int value; - throws_on_copy() - { - BOOST_TEST(++count()>0); - } - throws_on_copy( throws_on_copy const & ) - { - throw error(); - } - throws_on_copy( throws_on_copy && ) - { - BOOST_TEST(++count()>0); - } - ~throws_on_copy() - { - BOOST_TEST(--count()>=0); - } - }; - -struct A; -struct B; -struct C; - -void -run_tests() - { - using leaf::leaf_detail::tl_slot; - { - { - throws_on_copy a; - BOOST_TEST(count()==1); - auto & x = tl_slot::tl_instance(); - BOOST_TEST(!x.is_open()); - BOOST_TEST(!x.put(a)); - BOOST_TEST(count()==1); - BOOST_TEST(!x.has_value()); - BOOST_TEST(x.open()==1); - BOOST_TEST(x.put(throws_on_copy())); - BOOST_TEST(count()==2); - BOOST_TEST(x.has_value()); - try - { - (void) x.put(a); - BOOST_TEST(false); - } - catch( error & ) - { - } - BOOST_TEST(count()==1); - BOOST_TEST(!x.has_value()); - BOOST_TEST(x.is_open()); - BOOST_TEST(x.close()==0); - } - BOOST_TEST(count()==0); - { - auto & x = tl_slot>::tl_instance(); - BOOST_TEST(&x==&tl_slot>::tl_instance()); - BOOST_TEST(!x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(!x.put(my_info(42))); - BOOST_TEST(!x.has_value()); - BOOST_TEST(x.open()==1); - BOOST_TEST(x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(x.open()==2); - BOOST_TEST(x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(count>()==0); - BOOST_TEST(x.put(my_info(42))); - BOOST_TEST(x.close()==1); - BOOST_TEST(x.is_open()); - BOOST_TEST(x.has_value()); - BOOST_TEST(count>()==1); - BOOST_TEST(x.close()==0); - BOOST_TEST(!x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(count>()==0); - BOOST_TEST(x.open()==1); - BOOST_TEST(x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(count>()==0); - BOOST_TEST(x.put(my_info(43))); - BOOST_TEST(x.is_open()); - BOOST_TEST(x.has_value()); - BOOST_TEST(x.open()==2); - BOOST_TEST(x.is_open()); - BOOST_TEST(x.close()==1); - BOOST_TEST(x.close()==0); - BOOST_TEST(!x.has_value()); - } - { - auto & x = tl_slot>::tl_instance(); - BOOST_TEST(&x==&tl_slot>::tl_instance()); - BOOST_TEST(!x.is_open()); - BOOST_TEST(!x.has_value()); - { - my_info tmp(42); - BOOST_TEST(!x.put(tmp)); - } - BOOST_TEST(!x.has_value()); - BOOST_TEST(x.open()==1); - BOOST_TEST(x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(x.open()==2); - BOOST_TEST(x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(count>()==0); - { - my_info tmp(42); - BOOST_TEST(x.put(tmp)); - } - BOOST_TEST(x.close()==1); - BOOST_TEST(x.is_open()); - BOOST_TEST(x.has_value()); - BOOST_TEST(count>()==1); - BOOST_TEST(x.close()==0); - BOOST_TEST(!x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(count>()==0); - BOOST_TEST(x.open()==1); - BOOST_TEST(x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(count>()==0); - { - my_info tmp(43); - BOOST_TEST(x.put(tmp)); - } - BOOST_TEST(x.is_open()); - BOOST_TEST(x.has_value()); - BOOST_TEST(x.open()==2); - BOOST_TEST(x.is_open()); - BOOST_TEST(x.close()==1); - BOOST_TEST(x.close()==0); - BOOST_TEST(!x.has_value()); - } - { - auto & x = tl_slot>::tl_instance(); - BOOST_TEST(x.open()==1); - BOOST_TEST(x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(x.put(my_info(42))); - BOOST_TEST(x.has_value()); - x.reset(); - BOOST_TEST(x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(x.close()==0); - } - { - auto & x = tl_slot>::tl_instance(); - BOOST_TEST(x.open()==1); - BOOST_TEST(x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(x.put(my_info(42))); - BOOST_TEST(x.has_value()); - my_info inf = x.extract_value(); - BOOST_TEST(inf.value==42); - BOOST_TEST(x.is_open()); - BOOST_TEST(!x.has_value()); - BOOST_TEST(x.close()==0); - } - } - { - auto & x = tl_slot>::tl_instance(); - auto & y = tl_slot>::tl_instance(); - BOOST_TEST(x.open()==1); - BOOST_TEST(y.open()==1); - x.put(my_info(42)); - y.put(my_info(42)); - BOOST_TEST(x.has_value()); - BOOST_TEST(y.has_value()); - BOOST_TEST(count>()==1); - BOOST_TEST(count>()==1); - leaf::leaf_detail::tl_slot_base::bump_current_seq_id(); - BOOST_TEST(!x.has_value()); - BOOST_TEST(!y.has_value()); - BOOST_TEST(count>()==1); - BOOST_TEST(count>()==1); - BOOST_TEST(x.close()==0); - BOOST_TEST(y.close()==0); - } - BOOST_TEST(count>()==0); - BOOST_TEST(count>()==0); - BOOST_TEST(count>()==0); - } - -int -main() - { - std::vector> fut; - std::generate_n( std::inserter(fut,fut.end()), 100, [ ] - { - return std::async( std::launch::async, &run_tests ); - } ); - for( auto & i : fut ) - i.wait(); - for( auto & i : fut ) - i.get(); - return boost::report_errors(); - }