2
0
mirror of https://github.com/boostorg/leaf.git synced 2026-02-22 15:32:24 +00:00

Refactored on_error behavior in the presence of a dynamic allocator

This commit is contained in:
Emil Dotchevski
2026-02-11 18:29:21 -05:00
parent 552ff261e9
commit bd58aa238c
8 changed files with 20 additions and 480 deletions

View File

@@ -224,8 +224,6 @@ namespace detail
namespace detail
{
class preloaded_base;
template <class E>
struct capturing_slot_node_allocator;
@@ -238,8 +236,6 @@ namespace detail
template <class>
friend struct capturing_slot_node_allocator;
preloaded_base * preloaded_list_;
class capturing_node:
public capture_list::node
{
@@ -326,7 +322,6 @@ namespace detail
dynamic_allocator() noexcept:
capture_list(nullptr),
preloaded_list_(nullptr),
last_(&first_)
{
BOOST_LEAF_ASSERT(first_ == nullptr);
@@ -334,34 +329,14 @@ namespace detail
dynamic_allocator( dynamic_allocator && other ) noexcept:
capture_list(std::move(other)),
preloaded_list_(nullptr),
last_(other.last_ == &other.first_? &first_ : other.last_)
{
BOOST_LEAF_ASSERT(last_ != nullptr);
BOOST_LEAF_ASSERT(*last_ == nullptr);
BOOST_LEAF_ASSERT(other.first_ == nullptr);
BOOST_LEAF_ASSERT(other.preloaded_list_ == nullptr);
other.last_ = &other.first_;
}
preloaded_base * preloaded_list() const noexcept
{
return preloaded_list_;
}
preloaded_base * link_preloaded_item(preloaded_base * pb) noexcept
{
BOOST_LEAF_ASSERT(pb != nullptr);
preloaded_base * next = preloaded_list_;
preloaded_list_ = pb;
return next;
}
void unlink_preloaded_item(preloaded_base * next) noexcept
{
preloaded_list_ = next;
}
template <class E>
slot<E> * alloc()
{
@@ -606,38 +581,6 @@ namespace detail
namespace detail
{
#if BOOST_LEAF_CFG_CAPTURE
class preloaded_base
{
protected:
preloaded_base() noexcept:
next_(
[]( preloaded_base * this_ ) -> preloaded_base *
{
if( dynamic_allocator * da = get_dynamic_allocator() )
return da->link_preloaded_item(this_);
return nullptr;
}(this))
{
}
~preloaded_base() noexcept
{
if( dynamic_allocator * da = get_dynamic_allocator() )
da->unlink_preloaded_item(next_);
else
BOOST_LEAF_ASSERT(next_ == nullptr);
}
public:
preloaded_base * const next_;
virtual void reserve( dynamic_allocator & ) const = 0;
};
#endif // #if BOOST_LEAF_CFG_CAPTURE
inline int current_id() noexcept
{
unsigned id = tls::read_current_error_id();
@@ -652,13 +595,8 @@ namespace detail
return int(id);
}
inline int start_new_error() noexcept(!BOOST_LEAF_CFG_CAPTURE)
inline int start_new_error() noexcept
{
#if BOOST_LEAF_CFG_CAPTURE
if( dynamic_allocator * da = get_dynamic_allocator() )
for( preloaded_base const * e = da->preloaded_list(); e; e = e->next_ )
e->reserve(*da);
#endif
return new_id();
}

View File

@@ -40,19 +40,7 @@ public:
# else
if( std::uncaught_exception() )
# endif
# if BOOST_LEAF_CFG_CAPTURE
try
{
return detail::start_new_error();
}
catch(...)
{
BOOST_LEAF_ASSERT(detail::current_id() == err_id_);
return detail::new_id();
}
# else
return detail::start_new_error();
# endif
return detail::new_id();
#endif
return 0;
}
@@ -260,9 +248,6 @@ namespace detail
template <class... Item>
class preloaded
#if BOOST_LEAF_CFG_CAPTURE
: preloaded_base
#endif
{
preloaded( preloaded const & ) = delete;
preloaded & operator=( preloaded const & ) = delete;
@@ -273,13 +258,6 @@ namespace detail
bool moved_ = false;
#endif
#if BOOST_LEAF_CFG_CAPTURE
void reserve( dynamic_allocator & da ) const override
{
tuple_for_each_preload<sizeof...(Item),decltype(p_)>::reserve(p_,da);
}
#endif
public:
BOOST_LEAF_CONSTEXPR explicit preloaded( Item && ... i ):
@@ -302,8 +280,24 @@ namespace detail
if( moved_ )
return;
#endif
if( auto id = id_.check_id() )
tuple_for_each_preload<sizeof...(Item),decltype(p_)>::trigger(p_,id);
if( int const err_id = id_.check_id() )
{
#if BOOST_LEAF_CFG_CAPTURE
if( dynamic_allocator * da = get_dynamic_allocator() )
# ifndef BOOST_LEAF_NO_EXCEPTIONS
try
{
# endif
tuple_for_each_preload<sizeof...(Item),decltype(p_)>::reserve(p_, *da);
# ifndef BOOST_LEAF_NO_EXCEPTIONS
}
catch(...)
{
}
# endif
#endif
tuple_for_each_preload<sizeof...(Item),decltype(p_)>::trigger(p_, err_id);
}
}
};

View File

@@ -153,7 +153,6 @@ if option_enable_unit_tests
'on_error_accumulate_nested_new_error_result_test',
'on_error_accumulate_nested_success_exception_test',
'on_error_accumulate_nested_success_result_test',
'on_error_alloc_fail_test',
'on_error_defer_basic_test',
'on_error_defer_nested_error_exception_test',
'on_error_defer_nested_error_result_test',
@@ -162,8 +161,6 @@ if option_enable_unit_tests
'on_error_defer_nested_success_exception_test',
'on_error_defer_nested_success_result_test',
'on_error_dynamic_reserve_test1',
'on_error_dynamic_reserve_test2',
'on_error_dynamic_reserve_test3',
'on_error_preload_basic_test',
'on_error_preload_exception_test',
'on_error_preload_nested_error_exception_test',

View File

@@ -98,7 +98,6 @@ run on_error_accumulate_nested_new_error_exception_test.cpp ;
run on_error_accumulate_nested_new_error_result_test.cpp ;
run on_error_accumulate_nested_success_exception_test.cpp ;
run on_error_accumulate_nested_success_result_test.cpp ;
run on_error_alloc_fail_test.cpp ;
run on_error_defer_basic_test.cpp ;
run on_error_defer_nested_error_exception_test.cpp ;
run on_error_defer_nested_error_result_test.cpp ;
@@ -107,8 +106,6 @@ run on_error_defer_nested_new_error_result_test.cpp ;
run on_error_defer_nested_success_exception_test.cpp ;
run on_error_defer_nested_success_result_test.cpp ;
run on_error_dynamic_reserve_test1.cpp ;
run on_error_dynamic_reserve_test2.cpp ;
run on_error_dynamic_reserve_test3.cpp ;
run on_error_preload_basic_test.cpp ;
run on_error_preload_exception_test.cpp ;
run on_error_preload_nested_error_exception_test.cpp ;

View File

@@ -1,239 +0,0 @@
// Copyright 2018-2025 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)
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
# include "leaf.hpp"
#else
# include <boost/leaf/error.hpp>
# include <boost/leaf/on_error.hpp>
# include <boost/leaf/handle_errors.hpp>
# include <boost/leaf/result.hpp>
# include <boost/leaf/diagnostics.hpp>
# include <boost/leaf/exception.hpp>
#endif
#if !BOOST_LEAF_CFG_CAPTURE || defined(BOOST_LEAF_NO_EXCEPTIONS)
int main()
{
return 0;
}
#else
#include <sstream>
#include <stdexcept>
#include <string>
namespace leaf = boost::leaf;
struct alloc_fail_info
{
int value;
};
namespace boost { namespace leaf { namespace detail {
template <>
struct capturing_slot_node_allocator<alloc_fail_info>
{
template <class... A>
static dynamic_allocator::capturing_slot_node<alloc_fail_info> * new_( A && ... )
{
throw std::bad_alloc();
}
static void delete_( dynamic_allocator::capturing_slot_node<alloc_fail_info> * p ) noexcept
{
delete p;
}
};
} } } // namespace boost::leaf::detail
#include "lightweight_test.hpp"
template <int N>
struct other_info
{
int value;
};
leaf::result<void> f()
{
auto load = leaf::on_error( other_info<1>{1}, alloc_fail_info{42}, other_info<2>{2} );
return leaf::new_error();
}
int main()
{
{
auto captured = leaf::try_capture_all(
[]() -> leaf::result<void>
{
return f();
} );
int r = leaf::try_handle_all(
[&]() -> leaf::result<int>
{
(void) captured.value();
return 0;
},
[]( std::bad_alloc const &, other_info<1> const & oi1, other_info<2> const * oi2, alloc_fail_info const * afi )
{
BOOST_TEST_EQ(oi1.value, 1);
BOOST_TEST_EQ(oi2, nullptr);
BOOST_TEST_EQ(afi, nullptr);
return 1;
},
[]
{
return 2;
} );
BOOST_TEST_EQ(r, 1);
}
#if BOOST_LEAF_CFG_DIAGNOSTICS && BOOST_LEAF_CFG_STD_STRING
{
int r = leaf::try_handle_all(
[]() -> leaf::result<int>
{
BOOST_LEAF_CHECK(f());
return 0;
},
[]( std::bad_alloc const &, leaf::diagnostic_details const & dd )
{
std::ostringstream s;
s << dd;
std::string str = s.str();
BOOST_TEST(str.find("other_info<1>") != std::string::npos);
BOOST_TEST(str.find("other_info<2>") == std::string::npos);
BOOST_TEST(str.find("alloc_fail_info") == std::string::npos);
return 1;
},
[]
{
return 2;
} );
BOOST_TEST_EQ(r, 1);
}
#endif
////////////////////////////////////////
{
auto captured = leaf::try_capture_all(
[]() -> leaf::result<void>
{
auto load = leaf::on_error( other_info<1>{1}, alloc_fail_info{42}, other_info<2>{2} );
throw std::runtime_error("test");
} );
int r = leaf::try_handle_all(
[&]() -> leaf::result<int>
{
(void) captured.value();
return 0;
},
[]( other_info<1> const & oi1, other_info<2> const * oi2, alloc_fail_info const * afi )
{
BOOST_TEST_EQ(oi1.value, 1);
BOOST_TEST_EQ(oi2, nullptr);
BOOST_TEST_EQ(afi, nullptr);
return 1;
},
[]
{
return 2;
} );
BOOST_TEST_EQ(r, 1);
}
#if BOOST_LEAF_CFG_DIAGNOSTICS && BOOST_LEAF_CFG_STD_STRING
{
int r = leaf::try_catch(
[]() -> int
{
auto load = leaf::on_error( other_info<1>{1}, alloc_fail_info{42}, other_info<2>{2} );
throw std::runtime_error("test");
},
[]( leaf::diagnostic_details const & dd )
{
std::ostringstream s;
s << dd;
std::string str = s.str();
BOOST_TEST(str.find("other_info<1>") != std::string::npos);
BOOST_TEST(str.find("other_info<2>") == std::string::npos);
BOOST_TEST(str.find("alloc_fail_info") == std::string::npos);
return 1;
},
[]
{
return 2;
} );
BOOST_TEST_EQ(r, 1);
}
#endif
////////////////////////////////////////
{
auto captured = leaf::try_capture_all(
[]() -> leaf::result<void>
{
auto load = leaf::on_error( other_info<1>{1}, alloc_fail_info{42}, other_info<2>{2} );
leaf::throw_exception(std::runtime_error("test"));
} );
int r = leaf::try_handle_all(
[&]() -> leaf::result<int>
{
(void) captured.value();
return 0;
},
[]( std::bad_alloc const &, other_info<1> const & oi1, other_info<2> const * oi2, alloc_fail_info const * afi )
{
BOOST_TEST_EQ(oi1.value, 1);
BOOST_TEST_EQ(oi2, nullptr);
BOOST_TEST_EQ(afi, nullptr);
return 1;
},
[]
{
return 2;
} );
BOOST_TEST_EQ(r, 1);
}
#if BOOST_LEAF_CFG_DIAGNOSTICS && BOOST_LEAF_CFG_STD_STRING
{
int r = leaf::try_catch(
[]() -> int
{
auto load = leaf::on_error( other_info<1>{1}, alloc_fail_info{42}, other_info<2>{2} );
leaf::throw_exception(std::runtime_error("test"));
},
[]( std::bad_alloc const &, leaf::diagnostic_details const & dd )
{
std::ostringstream s;
s << dd;
std::string str = s.str();
BOOST_TEST(str.find("other_info<1>") != std::string::npos);
BOOST_TEST(str.find("other_info<2>") == std::string::npos);
BOOST_TEST(str.find("alloc_fail_info") == std::string::npos);
return 1;
},
[]
{
return 2;
} );
BOOST_TEST_EQ(r, 1);
}
#endif
return boost::report_errors();
}
#endif

View File

@@ -1,58 +0,0 @@
// Copyright 2018-2025 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)
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
# include "leaf.hpp"
#else
# include <boost/leaf/on_error.hpp>
# include <boost/leaf/handle_errors.hpp>
# include <boost/leaf/result.hpp>
# include <boost/leaf/config/tls.hpp>
# include <boost/leaf/diagnostics.hpp>
#endif
#include "lightweight_test.hpp"
namespace leaf = boost::leaf;
template <int N>
struct info
{
int value;
};
leaf::result<void> f()
{
BOOST_TEST_EQ(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>(), nullptr);
BOOST_TEST_NE(leaf::tls::read_ptr<leaf::detail::slot<info<43>>>(), nullptr);
auto load = leaf::on_error( info<42>{42} );
BOOST_TEST_EQ(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>(), nullptr);
auto e = leaf::new_error(info<43>{});
BOOST_TEST(
(BOOST_LEAF_CFG_CAPTURE == 0)
==
(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>() == nullptr));
return e;
}
int main()
{
int r = leaf::try_handle_all(
[]() -> leaf::result<int>
{
BOOST_LEAF_CHECK(f());
return 0;
},
[]( info<43> const & )
{
return 1;
},
[]( leaf::diagnostic_details const & )
{
return 2;
} );
BOOST_TEST_EQ(r, 1);
return boost::report_errors();
}

View File

@@ -1,74 +0,0 @@
// Copyright 2018-2025 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 <boost/leaf/config.hpp>
#if !BOOST_LEAF_CFG_CAPTURE
#include <iostream>
int main()
{
std::cout << "Unit test not applicable." << std::endl;
return 0;
}
#else
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
# include "leaf.hpp"
#else
# include <boost/leaf/on_error.hpp>
# include <boost/leaf/handle_errors.hpp>
# include <boost/leaf/result.hpp>
# include <boost/leaf/config/tls.hpp>
#endif
#include "lightweight_test.hpp"
namespace leaf = boost::leaf;
template <int N>
struct info
{
int value;
};
leaf::result<void> f()
{
BOOST_TEST_EQ(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>(), nullptr);
BOOST_TEST_NE(leaf::tls::read_ptr<leaf::detail::slot<info<43>>>(), nullptr);
auto load = leaf::on_error( info<42>{42} );
BOOST_TEST_EQ(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>(), nullptr);
auto e = leaf::new_error(info<43>{});
BOOST_TEST_NE(leaf::tls::read_ptr<leaf::detail::slot<info<42>>>(), nullptr);
return e;
}
int main()
{
int r = leaf::try_handle_all(
[]() -> leaf::result<int>
{
return leaf::try_capture_all(
[]() -> leaf::result<int>
{
BOOST_LEAF_CHECK(f());
return 0;
} );
},
[]( info<43> const & )
{
return 1;
},
[]
{
return 2;
} );
BOOST_TEST_EQ(r, 1);
return boost::report_errors();
}
#endif

View File

@@ -71,21 +71,6 @@ int main()
return leaf::new_error();
});
#if BOOST_LEAF_CFG_CAPTURE
(void) leaf::try_capture_all(
[]() -> leaf::result<void>
{
leaf::detail::dynamic_allocator * da = leaf::detail::get_dynamic_allocator();
BOOST_TEST_NE(da, nullptr);
BOOST_TEST_EQ(da->preloaded_list(), nullptr);
{
auto load = leaf::on_error( info<42>{42} );
BOOST_TEST_NE(da->preloaded_list(), nullptr);
}
BOOST_TEST_EQ(da->preloaded_list(), nullptr);
return { };
} );
#endif
return boost::report_errors();
}