Skip to content

Commit

Permalink
Improved behavior and testing when dynamic_cpture objects are nested.
Browse files Browse the repository at this point in the history
  • Loading branch information
zajo committed Dec 20, 2023
1 parent 506eee7 commit 22f8589
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 33 deletions.
10 changes: 5 additions & 5 deletions include/boost/leaf/detail/capture_list.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,6 @@ namespace leaf_detail
}
}

bool empty() const noexcept
{
return first_ == nullptr;
}

void unload( int const err_id )
{
capture_list moved(first_);
Expand All @@ -98,6 +93,11 @@ namespace leaf_detail
} );
}

bool empty() const noexcept
{
return first_ == nullptr;
}

template <class CharT, class Traits>
void print( std::basic_ostream<CharT, Traits> & os, char const * title, int const err_id_to_print ) const
{
Expand Down
23 changes: 19 additions & 4 deletions include/boost/leaf/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ namespace leaf_detail
#endif

int err_id_;
capture_list::node * * last_;
node * * last_;

public:

Expand All @@ -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 <class E>
typename std::decay<E>::type & dynamic_load(int err_id, E && e)
{
Expand Down Expand Up @@ -387,7 +398,6 @@ namespace leaf_detail
}

using capture_list::empty;
using capture_list::unload;
using capture_list::print;
};

Expand All @@ -414,8 +424,13 @@ namespace leaf_detail
template <>
inline void slot<dynamic_allocator>::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<slot<dynamic_allocator>>() )
if( dynamic_allocator * da2 = p->has_value(err_id) )
da2->append(std::move(*da1));
else
*p = std::move(*this);
}

template <class E>
Expand Down
204 changes: 180 additions & 24 deletions test/dynamic_capture_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,33 +28,38 @@ int main()

namespace leaf = boost::leaf;

template <int>
struct err
namespace
{
static int count;

err()
template <int>
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 N>
int err<N>::count = 0;
err( err && )
{
++count;
++move_count;
}

~err()
{
--count;
}
};
template <int N> int err<N>::count = 0;
template <int N> int err<N>::move_count = 0;
}

int main()
{
Expand All @@ -73,6 +78,7 @@ int main()
},
[]
{
BOOST_TEST(false);
});
BOOST_TEST_EQ(err<1>::count, 0);
BOOST_TEST_EQ(err<2>::count, 0);
Expand Down Expand Up @@ -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<int>
{
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);
Expand All @@ -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<int>
{
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<void> r = leaf::try_handle_some(
[]() -> leaf::result<void>
{
return leaf::try_handle_some(
[]() -> leaf::result<void>
{
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<void>
{
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<int>
{
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<void> r = leaf::try_handle_some(
[]() -> leaf::result<void>
{
return leaf::try_handle_some(
[]() -> leaf::result<void>
{
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<void>
{
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<int>
{
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();
}
Expand Down

0 comments on commit 22f8589

Please sign in to comment.