#ifndef BOOST_LEAF_ON_ERROR_HPP_INCLUDED #define BOOST_LEAF_ON_ERROR_HPP_INCLUDED // 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) #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_(leaf_detail::current_id()) { } int check_id() const noexcept { int err_id = leaf_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 leaf_detail::new_id(); #endif return 0; } } int get_id() const noexcept { int err_id = leaf_detail::current_id(); if( err_id != err_id_ ) return err_id; else return leaf_detail::new_id(); } error_id check() const noexcept { return leaf_detail::make_error_id(check_id()); } error_id assigned_error_id() const noexcept { return leaf_detail::make_error_id(get_id()); } }; //////////////////////////////////////////// namespace leaf_detail { template struct tuple_for_each_preload { BOOST_LEAF_CONSTEXPR static void trigger( Tuple & 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); } }; template struct tuple_for_each_preload<0, Tuple> { BOOST_LEAF_CONSTEXPR static void trigger( Tuple const &, int ) noexcept { } }; template class preloaded_item { using decay_E = typename std::decay::type; decay_E e_; public: BOOST_LEAF_CONSTEXPR preloaded_item( E && e ): e_(std::forward(e)) { } BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept { (void) load_slot(err_id, std::move(e_)); } }; template ::return_type> class deferred_item { F f_; public: BOOST_LEAF_CONSTEXPR deferred_item( F && f ) noexcept: f_(std::forward(f)) { } BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept { (void) load_slot_deferred(err_id, f_); } }; template class deferred_item { F f_; public: BOOST_LEAF_CONSTEXPR deferred_item( F && f ) noexcept: f_(std::forward(f)) { } BOOST_LEAF_CONSTEXPR void trigger( int ) noexcept { f_(); } }; template , int arity = function_traits::arity> class accumulating_item; template class accumulating_item { F f_; public: BOOST_LEAF_CONSTEXPR accumulating_item( F && f ) noexcept: f_(std::forward(f)) { } BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept { load_slot_accumulate(err_id, std::move(f_)); } }; template class preloaded { preloaded & operator=( preloaded const & ) = delete; std::tuple p_; bool moved_; error_monitor id_; public: BOOST_LEAF_CONSTEXPR explicit preloaded( Item && ... i ): p_(std::forward(i)...), moved_(false) { } BOOST_LEAF_CONSTEXPR preloaded( preloaded && x ) noexcept: p_(std::move(x.p_)), moved_(false), id_(std::move(x.id_)) { x.moved_ = true; } ~preloaded() noexcept { if( moved_ ) return; if( auto id = id_.check_id() ) tuple_for_each_preload::trigger(p_,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; }; } template BOOST_LEAF_ATTRIBUTE_NODISCARD BOOST_LEAF_CONSTEXPR inline leaf_detail::preloaded::type...> on_error( Item && ... i ) { return leaf_detail::preloaded::type...>(std::forward(i)...); } } } #endif