#ifndef BOOST_LEAF_ON_ERROR_HPP_INCLUDED #define BOOST_LEAF_ON_ERROR_HPP_INCLUDED // 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 #include namespace boost { namespace leaf { class error_monitor { #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS int const uncaught_exceptions_; #endif int const err_id_; public: error_monitor() noexcept: #if !defined(BOOST_LEAF_NO_EXCEPTIONS) && BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS uncaught_exceptions_(std::uncaught_exceptions()), #endif err_id_(detail::current_id()) { } int check_id() const noexcept { int err_id = detail::current_id(); if( err_id != err_id_ ) return err_id; else { #ifndef BOOST_LEAF_NO_EXCEPTIONS # if BOOST_LEAF_STD_UNCAUGHT_EXCEPTIONS if( std::uncaught_exceptions() > uncaught_exceptions_ ) # else if( std::uncaught_exception() ) # endif return detail::new_id(); #endif return 0; } } int get_id() const noexcept { int err_id = detail::current_id(); if( err_id != err_id_ ) return err_id; else return detail::new_id(); } error_id check() const noexcept { return detail::make_error_id(check_id()); } error_id assigned_error_id() const noexcept { return detail::make_error_id(get_id()); } }; // class error_monitor //////////////////////////////////////// namespace detail { template struct tuple_for_each_preload { BOOST_LEAF_CONSTEXPR static void trigger( Tup & tup, int err_id ) noexcept { BOOST_LEAF_ASSERT((err_id&3) == 1); tuple_for_each_preload::trigger(tup,err_id); std::get(tup).trigger(err_id); } #if BOOST_LEAF_CFG_CAPTURE static void reserve( Tup const & tup, dynamic_allocator & da ) { tuple_for_each_preload::reserve(tup,da); std::get(tup).reserve(da); } #endif }; template struct tuple_for_each_preload<0, Tup> { BOOST_LEAF_CONSTEXPR static void trigger( Tup const &, int ) noexcept { } #if BOOST_LEAF_CFG_CAPTURE static void reserve( Tup const &, dynamic_allocator & ) { } #endif }; template class preloaded_item { using E_decayed = typename std::decay::type; E_decayed e_; public: BOOST_LEAF_CONSTEXPR preloaded_item( E && e ): e_(std::forward(e)) { } BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept { if( slot * p = tls::read_ptr>() ) if( !p->has_value(err_id) ) (void) p->load(err_id, std::move(e_)); } #if BOOST_LEAF_CFG_CAPTURE void reserve( dynamic_allocator & da ) const { da.reserve(); } #endif }; template ::return_type> class deferred_item { using E_decayed = typename std::decay::type; F f_; public: BOOST_LEAF_CONSTEXPR deferred_item( F && f ): f_(std::forward(f)) { } void trigger( int err_id ) noexcept { if( slot * p = tls::read_ptr>() ) if( !p->has_value(err_id) ) { #ifndef BOOST_LEAF_NO_EXCEPTIONS try { #endif (void) p->load(err_id, f_()); #ifndef BOOST_LEAF_NO_EXCEPTIONS } catch(...) { } #endif } } #if BOOST_LEAF_CFG_CAPTURE void reserve( dynamic_allocator & da ) const { da.reserve(); } #endif }; template class deferred_item { F f_; public: BOOST_LEAF_CONSTEXPR deferred_item( F && f ) noexcept: f_(std::forward(f)) { } void trigger( int ) noexcept { #ifndef BOOST_LEAF_NO_EXCEPTIONS try { #endif f_(); #ifndef BOOST_LEAF_NO_EXCEPTIONS } catch(...) { } #endif } #if BOOST_LEAF_CFG_CAPTURE void reserve( dynamic_allocator & ) const { } #endif }; template , int arity = function_traits::arity> class accumulating_item; template class accumulating_item { using E_decayed = typename std::decay::type; F f_; public: BOOST_LEAF_CONSTEXPR accumulating_item( F && f ): f_(std::forward(f)) { } void trigger( int err_id ) noexcept { if( slot * p = tls::read_ptr>() ) { #ifndef BOOST_LEAF_NO_EXCEPTIONS try { #endif if( E_decayed * v = p->has_value(err_id) ) (void) std::move(f_)(*v); else (void) std::move(f_)(p->load(err_id, E_decayed())); #ifndef BOOST_LEAF_NO_EXCEPTIONS } catch(...) { } #endif } } #if BOOST_LEAF_CFG_CAPTURE void reserve( dynamic_allocator & da ) const { da.reserve(); } #endif }; template class preloaded { preloaded( preloaded const & ) = delete; preloaded & operator=( preloaded const & ) = delete; std::tuple p_; error_monitor id_; #if __cplusplus < 201703L bool moved_ = false; #endif public: BOOST_LEAF_CONSTEXPR explicit preloaded( Item && ... i ): p_(std::forward(i)...) { } #if __cplusplus < 201703L BOOST_LEAF_CONSTEXPR preloaded( preloaded && x ) noexcept: p_(std::move(x.p_)), id_(std::move(x.id_)) { x.moved_ = true; } #endif ~preloaded() noexcept { #if __cplusplus < 201703L if( moved_ ) return; #endif 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::reserve(p_, *da); # ifndef BOOST_LEAF_NO_EXCEPTIONS } catch(...) { } # endif #endif tuple_for_each_preload::trigger(p_, err_id); } } }; template ::arity> struct deduce_item_type; template struct deduce_item_type { using type = preloaded_item; }; template struct deduce_item_type { using type = deferred_item; }; template struct deduce_item_type { using type = accumulating_item; }; } // namespace detail template BOOST_LEAF_ATTRIBUTE_NODISCARD BOOST_LEAF_CONSTEXPR inline detail::preloaded::type...> on_error( Item && ... i ) { return detail::preloaded::type...>(std::forward(i)...); } } } // namespace boost::leaf #endif // #ifndef BOOST_LEAF_ON_ERROR_HPP_INCLUDED