#ifndef BOOST_LEAF_ON_ERROR_HPP_INCLUDED #define BOOST_LEAF_ON_ERROR_HPP_INCLUDED /// Copyright (c) 2018-2021 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) #ifndef BOOST_LEAF_ENABLE_WARNINGS /// # if defined(_MSC_VER) /// # pragma warning(push,1) /// # elif defined(__clang__) /// # pragma clang system_header /// # elif (__GNUC__*100+__GNUC_MINOR__>301) /// # pragma GCC system_header /// # endif /// #endif /// #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; slot * s_; decay_E e_; public: BOOST_LEAF_CONSTEXPR preloaded_item( E && e ): s_(tl_slot_ptr::p), e_(std::forward(e)) { } BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept { BOOST_LEAF_ASSERT((err_id&3)==1); if( s_ ) { if( !s_->has_value(err_id) ) s_->put(err_id, std::move(e_)); } #if BOOST_LEAF_DIAGNOSTICS else { int c = tl_unexpected_enabled<>::counter; BOOST_LEAF_ASSERT(c>=0); if( c ) load_unexpected(err_id, std::move(e_)); } #endif } }; template class deferred_item { using E = decltype(std::declval()()); slot * s_; F f_; public: BOOST_LEAF_CONSTEXPR deferred_item( F && f ) noexcept: s_(tl_slot_ptr::p), f_(std::forward(f)) { } BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept { BOOST_LEAF_ASSERT((err_id&3)==1); if( s_ ) { if( !s_->has_value(err_id) ) s_->put(err_id, f_()); } #if BOOST_LEAF_DIAGNOSTICS else { int c = tl_unexpected_enabled<>::counter; BOOST_LEAF_ASSERT(c>=0); if( c ) load_unexpected(err_id, std::forward(f_())); } #endif } }; template , int arity = function_traits::arity> class accumulating_item; template class accumulating_item { using E = A0; slot * s_; F f_; public: BOOST_LEAF_CONSTEXPR accumulating_item( F && f ) noexcept: s_(tl_slot_ptr::p), f_(std::forward(f)) { } BOOST_LEAF_CONSTEXPR void trigger( int err_id ) noexcept { BOOST_LEAF_ASSERT((err_id&3)==1); if( s_ ) if( E * e = s_->has_value(err_id) ) (void) f_(*e); else (void) f_(s_->put(err_id, E())); } }; 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_NODISCARD BOOST_LEAF_CONSTEXPR inline leaf_detail::preloaded::type...> on_error( Item && ... i ) { return leaf_detail::preloaded::type...>(std::forward(i)...); } } } #if defined(_MSC_VER) && !defined(BOOST_LEAF_ENABLE_WARNINGS) /// #pragma warning(pop) /// #endif /// #endif