#ifndef BOOST_LEAF_CAPTURE_HPP_INCLUDED #define BOOST_LEAF_CAPTURE_HPP_INCLUDED // Copyright 2018-2022 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 #include #if BOOST_LEAF_CFG_CAPTURE namespace boost { namespace leaf { namespace leaf_detail { template ::value> struct is_result_tag; template struct is_result_tag { }; template struct is_result_tag { }; } #ifdef BOOST_LEAF_NO_EXCEPTIONS namespace leaf_detail { template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) noexcept { auto active_context = activate_context(*ctx); return std::forward(f)(std::forward(a)...); } template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) noexcept { auto active_context = activate_context(*ctx); if( auto r = std::forward(f)(std::forward(a)...) ) return r; else { ctx->captured_id_ = r.error(); return std::move(ctx); } } template inline decltype(std::declval().get()) future_get_impl(is_result_tag, Future & fut) noexcept { return fut.get(); } template inline decltype(std::declval().get()) future_get_impl(is_result_tag, Future & fut) noexcept { if( auto r = fut.get() ) return r; else return error_id(r.error()); // unloads } } #else namespace leaf_detail { class capturing_exception: public std::exception { std::exception_ptr ex_; context_ptr ctx_; public: capturing_exception(std::exception_ptr && ex, context_ptr && ctx) noexcept: ex_(std::move(ex)), ctx_(std::move(ctx)) { BOOST_LEAF_ASSERT(ex_); BOOST_LEAF_ASSERT(ctx_); BOOST_LEAF_ASSERT(ctx_->captured_id_); } [[noreturn]] void unload_and_rethrow_original_exception() const { BOOST_LEAF_ASSERT(ctx_->captured_id_); tls::write_uint32(ctx_->captured_id_.value()); ctx_->propagate(ctx_->captured_id_); std::rethrow_exception(ex_); } template void print( std::basic_ostream & os ) const { ctx_->print(os); } }; template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) { auto active_context = activate_context(*ctx); error_monitor cur_err; try { return std::forward(f)(std::forward(a)...); } catch( capturing_exception const & ) { throw; } catch( exception_base const & e ) { ctx->captured_id_ = e.get_error_id(); leaf_detail::throw_exception_impl( capturing_exception(std::current_exception(), std::move(ctx)) ); } catch(...) { ctx->captured_id_ = cur_err.assigned_error_id(); leaf_detail::throw_exception_impl( capturing_exception(std::current_exception(), std::move(ctx)) ); } } template inline decltype(std::declval()(std::forward(std::declval())...)) capture_impl(is_result_tag, context_ptr && ctx, F && f, A... a) { auto active_context = activate_context(*ctx); error_monitor cur_err; try { if( auto && r = std::forward(f)(std::forward(a)...) ) return std::move(r); else { ctx->captured_id_ = r.error(); return std::move(ctx); } } catch( capturing_exception const & ) { throw; } catch( exception_base const & e ) { ctx->captured_id_ = e.get_error_id(); leaf_detail::throw_exception_impl( capturing_exception(std::current_exception(), std::move(ctx)) ); } catch(...) { ctx->captured_id_ = cur_err.assigned_error_id(); leaf_detail::throw_exception_impl( capturing_exception(std::current_exception(), std::move(ctx)) ); } } template inline decltype(std::declval().get()) future_get_impl(is_result_tag, Future & fut ) { try { return fut.get(); } catch( capturing_exception const & cap ) { cap.unload_and_rethrow_original_exception(); } } template inline decltype(std::declval().get()) future_get_impl(is_result_tag, Future & fut ) { try { if( auto r = fut.get() ) return r; else return error_id(r.error()); // unloads } catch( capturing_exception const & cap ) { cap.unload_and_rethrow_original_exception(); } } } #endif template inline decltype(std::declval()(std::forward(std::declval())...)) capture(context_ptr && ctx, F && f, A... a) { using namespace leaf_detail; return capture_impl(is_result_tag()(std::forward(std::declval())...))>(), std::move(ctx), std::forward(f), std::forward(a)...); } template inline decltype(std::declval().get()) future_get( Future & fut ) { using namespace leaf_detail; return future_get_impl(is_result_tag().get())>(), fut); } } } #endif #endif