diff --git a/include/boost/leaf/handle_errors.hpp b/include/boost/leaf/handle_errors.hpp index 3e36f19e..2ab3b766 100644 --- a/include/boost/leaf/handle_errors.hpp +++ b/include/boost/leaf/handle_errors.hpp @@ -874,7 +874,9 @@ namespace leaf_detail using R = decltype(std::declval()()); try { - return std::forward(try_block)(); + auto r = std::forward(try_block)(); + unload_result(&r); + return std::move(r); } catch( std::exception & ex ) { @@ -955,19 +957,39 @@ try_handle_some( TryBlock && try_block, H && ... h ) } template -BOOST_LEAF_CONSTEXPR inline +inline decltype(std::declval()()) try_catch( TryBlock && try_block, H && ... h ) { context_type_from_handlers ctx; auto active_context = activate_context(ctx); - return leaf_detail::try_catch_( - ctx, - [&] - { - return std::forward(try_block)(); - }, - std::forward(h)...); + using R = decltype(std::declval()()); + try + { + return std::forward(try_block)(); + } + catch( std::exception & ex ) + { + ctx.deactivate(); + error_info e(&ex); + return leaf_detail::handle_error_(ctx.tup(), e, std::forward(h)..., + [&]() -> R + { + ctx.unload(e.error()); + throw; + } ); + } + catch(...) + { + ctx.deactivate(); + error_info e(nullptr); + return leaf_detail::handle_error_(ctx.tup(), e, std::forward(h)..., + [&]() -> R + { + ctx.unload(e.error()); + throw; + } ); + } } #endif diff --git a/include/boost/leaf/result.hpp b/include/boost/leaf/result.hpp index 19d5e757..b7817723 100644 --- a/include/boost/leaf/result.hpp +++ b/include/boost/leaf/result.hpp @@ -557,14 +557,11 @@ class BOOST_LEAF_SYMBOL_VISIBLE result return error_id(error()).load(std::forward(item)...); } - void unload() noexcept + void unload() { #if BOOST_LEAF_CFG_CAPTURE if( what_.kind() == result_discriminant::err_id_capture_list ) - { - int err_id = what_.get_error_id().value(); - cap_.unload( err_id ); - } + cap_.unload(what_.get_error_id().value()); #endif } diff --git a/meson.build b/meson.build index a663abfb..1f6b1f84 100644 --- a/meson.build +++ b/meson.build @@ -116,6 +116,7 @@ if option_enable_unit_tests 'BOOST_LEAF_CHECK_test', 'capture_exception_async_test', 'capture_exception_result_async_test', + 'capture_exception_result_unload_test', 'capture_exception_state_test', 'capture_exception_unload_test', 'capture_result_async_test', diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index f19997d2..696495da 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -56,6 +56,7 @@ run BOOST_LEAF_CHECK_test.cpp ; run boost_exception_test.cpp ; run capture_exception_async_test.cpp ; run capture_exception_result_async_test.cpp ; +run capture_exception_result_unload_test.cpp ; run capture_exception_state_test.cpp ; run capture_exception_unload_test.cpp ; run capture_result_async_test.cpp ; diff --git a/test/capture_exception_result_async_test.cpp b/test/capture_exception_result_async_test.cpp index d37c8743..46ca00c5 100644 --- a/test/capture_exception_result_async_test.cpp +++ b/test/capture_exception_result_async_test.cpp @@ -73,8 +73,18 @@ std::vector launch_tasks( int task_count, F f ) int main() { - int const task_count = 1; + int const task_count = 100; int received_a, received_b; + + auto task = + []( int a, int b, int res ) -> leaf::result + { + if( res >= 0 ) + return res; + else + return leaf::new_error( info<1>{a}, info<2>{b}, info<3>{} ); + }; + auto error_handlers = std::make_tuple( [&]( info<1> const & x1, info<2> const & x2, info<4> const & ) { @@ -88,15 +98,7 @@ int main() } ); { - std::vector fut = launch_tasks( - task_count, - []( int a, int b, int res ) -> leaf::result - { - if( res >= 0 ) - return res; - else - return leaf::new_error( info<1>{a}, info<2>{b}, info<3>{} ); - } ); + std::vector fut = launch_tasks(task_count, task); for( auto & f : fut ) { @@ -114,22 +116,14 @@ int main() else { BOOST_TEST_EQ(r, -1); - BOOST_TEST_EQ(received_a, f.a); - BOOST_TEST_EQ(received_b, f.b); + BOOST_TEST_EQ(f.a, received_a); + BOOST_TEST_EQ(f.b, received_b); } } } { - std::vector fut = launch_tasks( - task_count, - []( int a, int b, int res ) -> leaf::result - { - if( res >= 0 ) - return res; - else - return leaf::new_error( info<1>{a}, info<2>{b}, info<3>{} ); - } ); + std::vector fut = launch_tasks(task_count, task); for( auto & f : fut ) { @@ -156,8 +150,8 @@ int main() else { BOOST_TEST_EQ(r, -1); - BOOST_TEST_EQ(received_a, f.a); - BOOST_TEST_EQ(received_b, f.b); + BOOST_TEST_EQ(f.a, received_a); + BOOST_TEST_EQ(f.b, received_b); } } } diff --git a/test/capture_exception_result_unload_test.cpp b/test/capture_exception_result_unload_test.cpp new file mode 100644 index 00000000..542cde51 --- /dev/null +++ b/test/capture_exception_result_unload_test.cpp @@ -0,0 +1,213 @@ +// Copyright 2018-2023 Emil Dotchevski and Reverge Studios, 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 + +#if defined(BOOST_LEAF_NO_EXCEPTIONS) || !BOOST_LEAF_CFG_CAPTURE + +#include + +int main() +{ + std::cout << "Unit test not applicable." << std::endl; + return 0; +} + +#else + +#ifdef BOOST_LEAF_TEST_SINGLE_HEADER +# include "leaf.hpp" +#else +# include +# include +# include +# include +#endif + +#include "_test_ec.hpp" +#include "lightweight_test.hpp" + +namespace leaf = boost::leaf; + +template struct info { int value; }; + +template +void test( F f ) +{ + { + int c=0; + auto r = f(); + leaf::try_handle_all( + [&r]() -> leaf::result + { + BOOST_LEAF_CHECK(std::move(r)); + return { }; + }, + [&c]( info<1> const & x ) + { + BOOST_TEST_EQ(x.value, 1); + BOOST_TEST_EQ(c, 0); + c = 1; + }, + [&c] + { + BOOST_TEST_EQ(c, 0); + c = 2; + } ); + BOOST_TEST_EQ(c, 1); + } + + { + int c=0; + auto r = f(); + leaf::try_handle_all( + [&r]() -> leaf::result + { + BOOST_LEAF_CHECK(std::move(r)); + return { }; + }, + [&c]( info<2> const & x ) + { + BOOST_TEST_EQ(x.value, 2); + BOOST_TEST_EQ(c, 0); + c = 1; + }, + [&c] + { + BOOST_TEST_EQ(c, 0); + c = 2; + } ); + BOOST_TEST_EQ(c, 2); + } + + { + auto r = f(); + int what = leaf::try_handle_all( + [&r]() -> leaf::result + { + BOOST_LEAF_CHECK(std::move(r)); + return 0; + }, + []( info<1> const & x ) + { + BOOST_TEST_EQ(x.value, 1); + return 1; + }, + [] + { + return 2; + } ); + BOOST_TEST_EQ(what, 1); + } + + { + auto r = f(); + int what = leaf::try_handle_all( + [&r]() -> leaf::result + { + BOOST_LEAF_CHECK(std::move(r)); + return 0; + }, + []( info<2> const & x ) + { + BOOST_TEST_EQ(x.value, 2); + return 1; + }, + [] + { + return 2; + } ); + BOOST_TEST_EQ(what, 2); + } +} + +int main() +{ + test( [] + { + return leaf::try_catch( + []() -> leaf::result + { + leaf::throw_exception(errc_a::a0, info<1>{1}, info<3>{3}); + }, + []( leaf::dynamic_capture const & cap ) -> leaf::result + { + return cap; + } ); + } ); + + test( [] + { + return leaf::try_catch( + []() -> leaf::result + { + leaf::throw_exception(errc_a::a0, info<1>{1}, info<3>{3}); + }, + []( leaf::dynamic_capture const & cap ) -> leaf::result + { + return cap; + } ); + } ); + + test( [] + { + return leaf::try_catch( + []() -> leaf::result + { + auto load = leaf::on_error(errc_a::a0, info<1>{1}, info<3>{3}); + leaf::throw_exception(); + }, + []( leaf::dynamic_capture const & cap ) -> leaf::result + { + return cap; + } ); + } ); + + test( [] + { + return leaf::try_catch( + []() -> leaf::result + { + auto load = leaf::on_error(errc_a::a0, info<1>{1}, info<3>{3}); + leaf::throw_exception(); + }, + []( leaf::dynamic_capture const & cap ) -> leaf::result + { + return cap; + } ); + } ); + + test( [] + { + return leaf::try_catch( + []() -> leaf::result + { + auto load = leaf::on_error(errc_a::a0, info<1>{1}, info<3>{3}); + throw std::exception(); + }, + []( leaf::dynamic_capture const & cap ) -> leaf::result + { + return cap; + } ); + } ); + + test( [] + { + return leaf::try_catch( + []() -> leaf::result + { + auto load = leaf::on_error(errc_a::a0, info<1>{1}, info<3>{3}); + throw std::exception(); + }, + []( leaf::dynamic_capture const & cap ) -> leaf::result + { + return cap; + } ); + } ); + + return boost::report_errors(); +} + +#endif diff --git a/test/capture_exception_state_test.cpp b/test/capture_exception_state_test.cpp index 72a9d7b7..e5bc5196 100644 --- a/test/capture_exception_state_test.cpp +++ b/test/capture_exception_state_test.cpp @@ -20,8 +20,8 @@ int main() #ifdef BOOST_LEAF_TEST_SINGLE_HEADER # include "leaf.hpp" #else -# include # include +# include # include #endif @@ -63,48 +63,49 @@ struct info int main() { - leaf::result r = leaf::try_handle_some( - []() -> leaf::result - { - leaf::throw_exception(info<1>{}, info<3>{}); - }, - [](leaf::dynamic_capture const & cap) -> leaf::result - { - BOOST_TEST(!cap.empty()); - BOOST_TEST_EQ(cap.size(), 2); - return cap; - } ); - BOOST_TEST_EQ(count, 2); - -#if BOOST_LEAF_CFG_STD_STRING { - std::ostringstream st; - st << r; - std::string s = st.str(); - std::cout << s << std::endl; - if( BOOST_LEAF_CFG_DIAGNOSTICS ) + leaf::result r = leaf::try_handle_some( + []() -> leaf::result + { + leaf::throw_exception(info<1>{}, info<3>{}); + }, + [](leaf::dynamic_capture const & cap) -> leaf::result + { + BOOST_TEST(!cap.empty()); + BOOST_TEST_EQ(cap.size(), 2); + return cap; + } ); + BOOST_TEST_EQ(count, 2); + + #if BOOST_LEAF_CFG_STD_STRING { - BOOST_TEST_NE(s.find("info<1> instance"), s.npos); - BOOST_TEST_NE(s.find("info<3> instance"), s.npos); + std::ostringstream st; + st << r; + std::string s = st.str(); + std::cout << s << std::endl; + if( BOOST_LEAF_CFG_DIAGNOSTICS ) + { + BOOST_TEST_NE(s.find("info<1> instance"), s.npos); + BOOST_TEST_NE(s.find("info<3> instance"), s.npos); + } } + #endif + + int ret = leaf::try_catch( + [&] + { + return r.value(); + }, + []( info<1>, info<3> ) + { + return 42; + }, + [] + { + return -42; + } ); + BOOST_TEST_EQ(ret, 42); } -#endif - - int ret = leaf::try_catch( - [&]() -> int - { - return r.value(); - }, - []( info<1>, info<3> ) - { - return 1; - }, - [] - { - return 2; - } ); - BOOST_TEST_EQ(ret, 1); - r = 0; BOOST_TEST_EQ(count, 0); return boost::report_errors(); diff --git a/test/capture_exception_unload_test.cpp b/test/capture_exception_unload_test.cpp index 8fff8dba..9be30b59 100644 --- a/test/capture_exception_unload_test.cpp +++ b/test/capture_exception_unload_test.cpp @@ -20,44 +20,29 @@ int main() #ifdef BOOST_LEAF_TEST_SINGLE_HEADER # include "leaf.hpp" #else -# include -# include # include +# include # include +# include #endif +#include "_test_ec.hpp" #include "lightweight_test.hpp" namespace leaf = boost::leaf; template struct info { int value; }; -template -void test( F f_ ) +template +void test( F f ) { - auto f = - [=] - { - return leaf::try_handle_some( - [&]() -> leaf::result - { - f_(); - BOOST_TEST(false); - return { }; - }, - []( leaf::dynamic_capture const & cap ) -> leaf::result - { - return cap; - }); - }; - { int c=0; - leaf::result r = f(); + auto r = f(); leaf::try_catch( [&r] { - return r.value(); + (void) r.value(); }, [&c]( info<1> const & x ) { @@ -75,11 +60,11 @@ void test( F f_ ) { int c=0; - leaf::result r = f(); + auto r = f(); leaf::try_catch( [&r] { - return r.value(); + (void) r.value(); }, [&c]( info<2> const & x ) { @@ -96,7 +81,7 @@ void test( F f_ ) } { - leaf::result r = f(); + auto r = f(); int what = leaf::try_catch( [&r] { @@ -116,7 +101,7 @@ void test( F f_ ) } { - leaf::result r = f(); + auto r = f(); int what = leaf::try_catch( [&r] { @@ -134,85 +119,92 @@ void test( F f_ ) } ); BOOST_TEST_EQ(what, 2); } +} +int main() +{ + test( [] { - leaf::result r = f(); - bool what = leaf::try_catch( - [&r] + return leaf::try_handle_some( + []() -> leaf::result { - (void) r.value(); - return true; + leaf::throw_exception(errc_a::a0, info<1>{1}, info<3>{3}); }, - []( info<1> const &, info<2> const & ) + []( leaf::dynamic_capture const & cap ) -> leaf::result { - return true; - }, - []( info<1> const & x, info<3> const & y ) + return cap; + } ); + } ); + + test( [] + { + return leaf::try_handle_some( + []() -> leaf::result { - BOOST_TEST_EQ(x.value, 1); - BOOST_TEST_EQ(y.value, 3); - return false; + leaf::throw_exception(errc_a::a0, info<1>{1}, info<3>{3}); }, - []( info<1> const & ) + []( leaf::dynamic_capture const & cap ) -> leaf::result { - return true; + return cap; + } ); + } ); + + test( [] + { + return leaf::try_handle_some( + []() -> leaf::result + { + auto load = leaf::on_error(errc_a::a0, info<1>{1}, info<3>{3}); + leaf::throw_exception(); }, - [] + []( leaf::dynamic_capture const & cap ) -> leaf::result { - return true; + return cap; } ); - BOOST_TEST(!what); - } + } ); + test( [] { - leaf::result r = f(); - bool what = leaf::try_catch( - [&r] + return leaf::try_handle_some( + []() -> leaf::result { - (void) r.value(); - return false; + auto load = leaf::on_error(errc_a::a0, info<1>{1}, info<3>{3}); + leaf::throw_exception(); }, - []( info<1> const &, info<2> const & ) + []( leaf::dynamic_capture const & cap ) -> leaf::result { - return false; - }, - []( info<1> const & x, info<3> const & y ) + return cap; + } ); + } ); + + test( [] + { + return leaf::try_handle_some( + []() -> leaf::result { - BOOST_TEST_EQ(x.value, 1); - BOOST_TEST_EQ(y.value, 3); - return true; + auto load = leaf::on_error(errc_a::a0, info<1>{1}, info<3>{3}); + throw std::exception(); }, - []( info<1> const & ) + []( leaf::dynamic_capture const & cap ) -> leaf::result { - return false; + return cap; + } ); + } ); + + test( [] + { + return leaf::try_handle_some( + []() -> leaf::result + { + auto load = leaf::on_error(errc_a::a0, info<1>{1}, info<3>{3}); + throw std::exception(); }, - [] + []( leaf::dynamic_capture const & cap ) -> leaf::result { - return false; + return cap; } ); - BOOST_TEST(what); - } -} + } ); -int main() -{ - test, info<2>, info<3>>( - [] - { - leaf::throw_exception(info<1>{1}, info<3>{3}); // Derives from leaf::leaf::error_id - } ); - test, info<2>, info<3>>( - [] - { - auto load = leaf::on_error( info<1>{1}, info<3>{3} ); - leaf::throw_exception(); // Derives from leaf::leaf::error_id - } ); - test, info<2>, info<3>>( - [] - { - auto load = leaf::on_error( info<1>{1}, info<3>{3} ); - throw std::exception(); // Does not derive from leaf::leaf::error_id - } ); return boost::report_errors(); } diff --git a/test/capture_result_state_test.cpp b/test/capture_result_state_test.cpp index 6839949d..7e1461ae 100644 --- a/test/capture_result_state_test.cpp +++ b/test/capture_result_state_test.cpp @@ -68,8 +68,10 @@ int main() { return leaf::new_error( info<1>{}, info<3>{} ); }, - []( leaf::dynamic_capture const & cap ) -> leaf::result + [](leaf::dynamic_capture const & cap) -> leaf::result { + BOOST_TEST(!cap.empty()); + BOOST_TEST_EQ(cap.size(), 2); return cap; } ); BOOST_TEST_EQ(count, 2); @@ -88,8 +90,8 @@ int main() } #endif - int answer = leaf::try_handle_all( - [&r] + int ret = leaf::try_handle_all( + [&] { return std::move(r); }, @@ -101,7 +103,7 @@ int main() { return -42; } ); - BOOST_TEST_EQ(answer, 42); + BOOST_TEST_EQ(ret, 42); } BOOST_TEST_EQ(count, 0); diff --git a/test/capture_result_unload_test.cpp b/test/capture_result_unload_test.cpp index b9c1b99a..bc988a8e 100644 --- a/test/capture_result_unload_test.cpp +++ b/test/capture_result_unload_test.cpp @@ -22,6 +22,7 @@ int main() #else # include # include +# include #endif #include "_test_ec.hpp" @@ -149,6 +150,34 @@ int main() } ); } ); + test( [] + { + return leaf::try_handle_some( + []() -> leaf::result + { + auto load = leaf::on_error(errc_a::a0, info<1>{1}, info<3>{3}); + return leaf::new_error(); + }, + []( leaf::dynamic_capture const & cap ) -> leaf::result + { + return cap; + } ); + } ); + + test( [] + { + return leaf::try_handle_some( + []() -> leaf::result + { + auto load = leaf::on_error(errc_a::a0, info<1>{1}, info<3>{3}); + return leaf::new_error(); + }, + []( leaf::dynamic_capture const & cap ) -> leaf::result + { + return cap; + } ); + } ); + return boost::report_errors(); } diff --git a/test/handle_some_test.cpp b/test/handle_some_test.cpp index 1950d381..5705a8da 100644 --- a/test/handle_some_test.cpp +++ b/test/handle_some_test.cpp @@ -1453,7 +1453,8 @@ int main() [] { return 2; - }); + }); + BOOST_TEST_EQ(r, 1); } #ifndef BOOST_LEAF_NO_EXCEPTIONS