diff --git a/include/boost/leaf/detail/capture_list.hpp b/include/boost/leaf/detail/capture_list.hpp index 1c9dfc23..38497413 100644 --- a/include/boost/leaf/detail/capture_list.hpp +++ b/include/boost/leaf/detail/capture_list.hpp @@ -81,11 +81,6 @@ namespace leaf_detail } } - bool empty() const noexcept - { - return first_ == nullptr; - } - void unload( int const err_id ) { capture_list moved(first_); @@ -98,6 +93,11 @@ namespace leaf_detail } ); } + bool empty() const noexcept + { + return first_ == nullptr; + } + template void print( std::basic_ostream & os, char const * title, int const err_id_to_print ) const { diff --git a/include/boost/leaf/error.hpp b/include/boost/leaf/error.hpp index bb36a0fc..cf8efee8 100644 --- a/include/boost/leaf/error.hpp +++ b/include/boost/leaf/error.hpp @@ -317,7 +317,7 @@ namespace leaf_detail #endif int err_id_; - capture_list::node * * last_; + node * * last_; public: @@ -340,6 +340,17 @@ namespace leaf_detail other.last_ = &other.first_; } + BOOST_LEAF_CONSTEXPR void append( dynamic_allocator && other ) noexcept + { + if( node * other_first = other.first_ ) + { + *last_ = other_first; + last_ = other.last_; + other.first_ = nullptr; + other.last_ = &other.first_; + } + } + template typename std::decay::type & dynamic_load(int err_id, E && e) { @@ -387,7 +398,6 @@ namespace leaf_detail } using capture_list::empty; - using capture_list::unload; using capture_list::print; }; @@ -414,8 +424,13 @@ namespace leaf_detail template <> inline void slot::unload( int err_id ) noexcept(false) { - if( dynamic_allocator * c = this->has_value(err_id) ) - c->unload(err_id); + BOOST_LEAF_ASSERT(err_id); + if( dynamic_allocator * da1 = this->has_value(err_id) ) + if( impl * p = tls::read_ptr>() ) + if( dynamic_allocator * da2 = p->has_value(err_id) ) + da2->append(std::move(*da1)); + else + *p = std::move(*this); } template diff --git a/test/dynamic_capture_test.cpp b/test/dynamic_capture_test.cpp index 5401679f..757e8706 100644 --- a/test/dynamic_capture_test.cpp +++ b/test/dynamic_capture_test.cpp @@ -28,33 +28,38 @@ int main() namespace leaf = boost::leaf; -template -struct err +namespace { - static int count; - - err() + template + struct err { - ++count; - } + static int count; + static int move_count; - err( err const & ) - { - ++count; - } + err() + { + ++count; + } - err( err && ) - { - ++count; - } + err( err const & ) + { + ++count; + } - ~err() - { - --count; - } -}; -template -int err::count = 0; + err( err && ) + { + ++count; + ++move_count; + } + + ~err() + { + --count; + } + }; + template int err::count = 0; + template int err::move_count = 0; +} int main() { @@ -73,6 +78,7 @@ int main() }, [] { + BOOST_TEST(false); }); BOOST_TEST_EQ(err<1>::count, 0); BOOST_TEST_EQ(err<2>::count, 0); @@ -109,9 +115,24 @@ int main() BOOST_TEST(!cap.empty()); return cap; } ); + BOOST_TEST(!r); BOOST_TEST_EQ(err<1>::count, 1); BOOST_TEST_EQ(err<2>::count, 1); - (void) r; + int r1 = leaf::try_handle_all( + [&]() -> leaf::result + { + BOOST_LEAF_CHECK(r); + return 0; + }, + [](err<1>, err<2>) + { + return 1; + }, + [] + { + return 2; + } ); + BOOST_TEST_EQ(r1, 1); } BOOST_TEST_EQ(err<1>::count, 0); BOOST_TEST_EQ(err<2>::count, 0); @@ -130,12 +151,147 @@ int main() BOOST_TEST(!cap.empty()); return cap; } ); + BOOST_TEST(!r); + BOOST_TEST_EQ(err<1>::count, 1); + BOOST_TEST_EQ(err<2>::count, 1); + int r1 = leaf::try_handle_all( + [&]() -> leaf::result + { + BOOST_LEAF_CHECK(r); + return 0; + }, + [](err<1>, err<2>) + { + return 1; + }, + [] + { + return 2; + } ); + BOOST_TEST_EQ(r1, 1); + } + BOOST_TEST_EQ(err<1>::count, 0); + BOOST_TEST_EQ(err<2>::count, 0); + + // nested/unload + { + leaf::result r = leaf::try_handle_some( + []() -> leaf::result + { + return leaf::try_handle_some( + []() -> leaf::result + { + return leaf::new_error(err<1>{}, err<2>{}, err<3>{}); + }, + []( err<3>, err<4> ) + { + BOOST_TEST(false); + }, + [&]( leaf::error_info const & ei, leaf::dynamic_capture const & cap ) + { + BOOST_TEST_EQ(err<1>::count, 1); + BOOST_TEST_EQ(err<2>::count, 1); + BOOST_TEST_EQ(err<3>::count, 1); + BOOST_TEST_EQ(cap.size(), 2); + BOOST_TEST(!cap.empty()); + err<1>::move_count = 0; + err<2>::move_count = 0; + return ei.error(); + } ); + }, + []( leaf::dynamic_capture const & cap ) -> leaf::result + { + BOOST_TEST_EQ(err<1>::count, 1); + BOOST_TEST_EQ(err<2>::count, 1); + BOOST_TEST_EQ(err<3>::count, 1); + BOOST_TEST_EQ(cap.size(), 3); + BOOST_TEST(!cap.empty()); + return cap; + } ); + BOOST_TEST_EQ(err<1>::count, 1); + BOOST_TEST_EQ(err<2>::count, 1); + BOOST_TEST_EQ(err<3>::count, 1); + BOOST_TEST_EQ(err<1>::move_count, 0); + BOOST_TEST_EQ(err<2>::move_count, 0); + int r1 = leaf::try_handle_all( + [&]() -> leaf::result + { + BOOST_LEAF_CHECK(r); + return 0; + }, + [](err<1>, err<2>) + { + return 1; + }, + [] + { + return 2; + } ); + BOOST_TEST_EQ(r1, 1); + } + BOOST_TEST_EQ(err<1>::count, 0); + BOOST_TEST_EQ(err<2>::count, 0); + BOOST_TEST_EQ(err<3>::count, 0); + + // nested/unload, different order + { + leaf::result r = leaf::try_handle_some( + []() -> leaf::result + { + return leaf::try_handle_some( + []() -> leaf::result + { + return leaf::new_error(err<1>{}, err<2>{}, err<3>{}); + }, + [&]( leaf::error_info const & ei, leaf::dynamic_capture const & cap ) + { + BOOST_TEST_EQ(err<1>::count, 1); + BOOST_TEST_EQ(err<2>::count, 1); + BOOST_TEST_EQ(err<3>::count, 1); + BOOST_TEST_EQ(cap.size(), 2); + BOOST_TEST(!cap.empty()); + err<1>::move_count = 0; + err<2>::move_count = 0; + return ei.error(); + }, + []( err<3>, err<4> ) + { + BOOST_TEST(false); + } ); + }, + []( leaf::dynamic_capture const & cap ) -> leaf::result + { + BOOST_TEST_EQ(err<1>::count, 1); + BOOST_TEST_EQ(err<2>::count, 1); + BOOST_TEST_EQ(err<3>::count, 1); + BOOST_TEST_EQ(cap.size(), 3); + BOOST_TEST(!cap.empty()); + return cap; + } ); BOOST_TEST_EQ(err<1>::count, 1); BOOST_TEST_EQ(err<2>::count, 1); - (void) r; + BOOST_TEST_EQ(err<3>::count, 1); + BOOST_TEST_EQ(err<1>::move_count, 0); + BOOST_TEST_EQ(err<2>::move_count, 0); + int r1 = leaf::try_handle_all( + [&]() -> leaf::result + { + BOOST_LEAF_CHECK(r); + return 0; + }, + [](err<1>, err<2>) + { + return 1; + }, + [] + { + return 2; + } ); + BOOST_TEST_EQ(r1, 1); } BOOST_TEST_EQ(err<1>::count, 0); BOOST_TEST_EQ(err<2>::count, 0); + BOOST_TEST_EQ(err<3>::count, 0); return boost::report_errors(); }