2
0
mirror of https://github.com/boostorg/leaf.git synced 2026-01-19 04:22:08 +00:00

Fix a bug in dynamic_allocator

This commit is contained in:
Emil Dotchevski
2024-06-30 16:37:26 -07:00
parent 5ed2782f05
commit d755b4ce1c
5 changed files with 206 additions and 35 deletions

View File

@@ -134,6 +134,16 @@ namespace leaf_detail
return value_;
}
BOOST_LEAF_CONSTEXPR T const * has_value() const noexcept
{
return key_ ? &value_ : nullptr;
}
BOOST_LEAF_CONSTEXPR T * has_value() noexcept
{
return key_ ? &value_ : nullptr;
}
BOOST_LEAF_CONSTEXPR T const * has_value(int key) const noexcept
{
BOOST_LEAF_ASSERT(key);

View File

@@ -111,6 +111,11 @@ namespace leaf_detail
BOOST_LEAF_ASSERT(x.prev_==nullptr);
}
~slot() noexcept
{
BOOST_LEAF_ASSERT(tls::read_ptr<slot<E>>() != this);
}
void activate() noexcept
{
prev_ = tls::read_ptr<slot<E>>();
@@ -240,7 +245,7 @@ namespace leaf_detail
public:
explicit capturing_exception_node( capture_list::node * * & last, std::exception_ptr && ex ) noexcept:
capturing_exception_node( capture_list::node * * & last, std::exception_ptr && ex ) noexcept:
capturing_node(last),
ex_(std::move(ex))
{
@@ -250,14 +255,12 @@ namespace leaf_detail
};
#endif
int err_id_;
node * * last_;
public:
dynamic_allocator() noexcept:
capture_list(nullptr),
err_id_(0),
last_(&first_)
{
BOOST_LEAF_ASSERT(first_ == nullptr);
@@ -265,7 +268,6 @@ namespace leaf_detail
dynamic_allocator( dynamic_allocator && other ) noexcept:
capture_list(std::move(other)),
err_id_(other.err_id_),
last_(other.last_ == &other.first_? &first_ : other.last_)
{
BOOST_LEAF_ASSERT(last_ != nullptr);
@@ -274,17 +276,6 @@ namespace leaf_detail
other.last_ = &other.first_;
}
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)
{
@@ -294,7 +285,6 @@ namespace leaf_detail
BOOST_LEAF_ASSERT(tls::read_ptr<slot<T>>() == nullptr);
capturing_slot_node<T> * csn = new capturing_slot_node<T>(last_, err_id, std::forward<E>(e));
csn->activate();
err_id_ = err_id;
return csn->value(err_id);
}
@@ -308,7 +298,7 @@ namespace leaf_detail
}
template <class LeafResult>
LeafResult extract_capture_list() noexcept
LeafResult extract_capture_list(int err_id) noexcept
{
#ifndef BOOST_LEAF_NO_EXCEPTIONS
if( std::exception_ptr ex = std::current_exception() )
@@ -317,9 +307,10 @@ namespace leaf_detail
leaf_detail::capture_list::node * const f = first_;
first_ = nullptr;
last_ = &first_;
return { err_id_, capture_list(f) };
return { err_id, capture_list(f) };
}
using capture_list::unload;
using capture_list::print;
};
@@ -337,9 +328,8 @@ namespace leaf_detail
template <>
inline void slot<dynamic_allocator>::deactivate() const noexcept
{
if( int const err_id = this->key() )
if( dynamic_allocator const * c = this->has_value(err_id) )
c->deactivate();
if( dynamic_allocator const * c = this->has_value() )
c->deactivate();
tls::write_ptr<slot<dynamic_allocator>>(prev_);
}
@@ -347,12 +337,8 @@ namespace leaf_detail
inline void slot<dynamic_allocator>::unload( int err_id ) noexcept(false)
{
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);
if( dynamic_allocator * da1 = this->has_value() )
da1->unload(err_id);
}
template <class E>
@@ -360,7 +346,7 @@ namespace leaf_detail
{
if( slot<dynamic_allocator> * sl = tls::read_ptr<slot<dynamic_allocator>>() )
{
if( dynamic_allocator * c = sl->has_value(err_id) )
if( dynamic_allocator * c = sl->has_value() )
c->dynamic_load(err_id, std::forward<E>(e));
else
sl->load(err_id).dynamic_load(err_id, std::forward<E>(e));
@@ -435,7 +421,10 @@ namespace leaf_detail
if( this->key()!=err_id )
return;
if( impl * p = tls::read_ptr<slot<E>>() )
*p = std::move(*this);
{
if( !p->has_value(err_id) )
*p = std::move(*this);
}
#if BOOST_LEAF_CFG_CAPTURE
else
dynamic_load<false>(err_id, std::move(*this).value(err_id));

View File

@@ -226,6 +226,36 @@ protected:
namespace leaf_detail
{
template <class T>
struct get_dispatch
{
static BOOST_LEAF_CONSTEXPR T const * get(T const * x) noexcept
{
return x;
}
static BOOST_LEAF_CONSTEXPR T const * get(void const *) noexcept
{
return nullptr;
}
};
template <class T, int I = 0, class... Tp>
BOOST_LEAF_CONSTEXPR inline typename std::enable_if<I == sizeof...(Tp) - 1, T>::type const *
find_in_tuple(std::tuple<Tp...> const & t) noexcept
{
return get_dispatch<T>::get(&std::get<I>(t));
}
template<class T, int I = 0, class... Tp>
BOOST_LEAF_CONSTEXPR inline typename std::enable_if<I < sizeof...(Tp) - 1, T>::type const *
find_in_tuple(std::tuple<Tp...> const & t) noexcept
{
if( T const * x = get_dispatch<T>::get(&std::get<I>(t)) )
return x;
else
return find_in_tuple<T, I+1, Tp...>(t);
}
struct verbose_diagnostic_info_: verbose_diagnostic_info
{
template <class Tup>
@@ -241,7 +271,8 @@ namespace leaf_detail
template <class Tup>
BOOST_LEAF_CONSTEXPR static verbose_diagnostic_info_ get( Tup const & tup, error_info const & ei ) noexcept
{
return verbose_diagnostic_info_(ei, tup, handler_argument_traits_defaults<dynamic_allocator>::check(tup, ei));
slot<dynamic_allocator> const * da = find_in_tuple<slot<dynamic_allocator>>(tup);
return verbose_diagnostic_info_(ei, tup, da ? da->has_value() : nullptr );
}
};
}
@@ -945,19 +976,22 @@ namespace leaf_detail
else
{
sl.deactivate();
return leaf_result(sl.value(error_id(r.error()).value()).template extract_capture_list<leaf_result>());
int const err_id = error_id(r.error()).value();
return leaf_result(sl.value(err_id).template extract_capture_list<leaf_result>(err_id));
}
}
#ifndef BOOST_LEAF_NO_EXCEPTIONS
catch( std::exception & ex )
{
sl.deactivate();
return sl.value(error_info(&ex).error().value()).template extract_capture_list<leaf_result>();
int const err_id = error_info(&ex).error().value();
return sl.value(err_id).template extract_capture_list<leaf_result>(err_id);
}
catch(...)
{
sl.deactivate();
return sl.value(error_info(nullptr).error().value()).template extract_capture_list<leaf_result>();
int const err_id = error_info(nullptr).error().value();
return sl.value(err_id).template extract_capture_list<leaf_result>(err_id);
}
#endif
}
@@ -1002,12 +1036,14 @@ namespace leaf_detail
catch( std::exception & ex )
{
sl.deactivate();
return sl.value(error_info(&ex).error().value()).template extract_capture_list<leaf_result>();
int const err_id = error_info(&ex).error().value();
return sl.value(err_id).template extract_capture_list<leaf_result>(err_id);
}
catch(...)
{
sl.deactivate();
return sl.value(error_info(nullptr).error().value()).template extract_capture_list<leaf_result>();
int const err_id = error_info(nullptr).error().value();
return sl.value(err_id).template extract_capture_list<leaf_result>(err_id);
}
#endif
}

View File

@@ -127,6 +127,7 @@ if option_enable_unit_tests
'diagnostic_info_test3',
'diagnostic_info_test4',
'diagnostic_info_test5',
'diagnostic_info_test6',
'e_errno_test',
'e_LastError_test',
'error_code_test',

View File

@@ -0,0 +1,135 @@
// 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)
#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
# include "leaf.hpp"
#else
# include <boost/leaf/config.hpp>
# include <boost/leaf/handle_errors.hpp>
# include <boost/leaf/on_error.hpp>
# include <boost/leaf/result.hpp>
#endif
#if BOOST_LEAF_CFG_STD_STRING
# include <sstream>
# include <iostream>
#endif
#include <vector>
#include "lightweight_test.hpp"
namespace leaf = boost::leaf;
template <int> struct info { int value; };
leaf::result<void> f1()
{
return leaf::new_error(info<1>{11}, info<2>{21});
}
leaf::result<void> f2()
{
return leaf::try_handle_some(
[]
{
return f1();
},
[]
{
return leaf::new_error(info<1>{12});
} );
}
leaf::result<void> f3()
{
return leaf::try_handle_some(
[]
{
return f1();
},
[](leaf::verbose_diagnostic_info const &)
{
return leaf::new_error(info<1>{13});
} );
}
leaf::result<void> f4()
{
return leaf::try_handle_some(
[]
{
return f1();
},
[](leaf::verbose_diagnostic_info const & e)
{
return e.error().load(info<1>{14});
} );
}
int main()
{
leaf::try_handle_all([]() -> leaf::result<void>
{
return f2();
},
[](leaf::verbose_diagnostic_info const & e)
{
#if BOOST_LEAF_CFG_STD_STRING
std::ostringstream st;
st << e;
std::string s = st.str();
std::cout << s << std::endl;
if( BOOST_LEAF_CFG_DIAGNOSTICS && BOOST_LEAF_CFG_CAPTURE )
{
BOOST_TEST_EQ(s.find(": 11"), s.npos);
BOOST_TEST_NE(s.find(": 12"), s.npos);
BOOST_TEST_EQ(s.find(": 21"), s.npos);
}
#endif
} );
leaf::try_handle_all([]() -> leaf::result<void>
{
return f3();
},
[](leaf::verbose_diagnostic_info const & e)
{
#if BOOST_LEAF_CFG_STD_STRING
std::ostringstream st;
st << e;
std::string s = st.str();
std::cout << s << std::endl;
if( BOOST_LEAF_CFG_DIAGNOSTICS && BOOST_LEAF_CFG_CAPTURE )
{
BOOST_TEST_EQ(s.find(": 11"), s.npos);
BOOST_TEST_NE(s.find(": 13"), s.npos);
BOOST_TEST_EQ(s.find(": 21"), s.npos);
}
#endif
} );
leaf::try_handle_all([]() -> leaf::result<void>
{
return f4();
},
[](leaf::verbose_diagnostic_info const & e)
{
#if BOOST_LEAF_CFG_STD_STRING
std::ostringstream st;
st << e;
std::string s = st.str();
std::cout << s << std::endl;
if( BOOST_LEAF_CFG_DIAGNOSTICS && BOOST_LEAF_CFG_CAPTURE )
{
BOOST_TEST_EQ(s.find(": 12"), s.npos);
BOOST_TEST_NE(s.find(": 14"), s.npos);
BOOST_TEST_NE(s.find(": 21"), s.npos);
}
#endif
} );
return boost::report_errors();
}