// // impl/use_future.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // 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 ASIO_IMPL_USE_FUTURE_HPP #define ASIO_IMPL_USE_FUTURE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include "asio/detail/config.hpp" #include #include "asio/async_result.hpp" #include "asio/detail/memory.hpp" #include "asio/dispatch.hpp" #include "asio/error_code.hpp" #include "asio/execution.hpp" #include "asio/packaged_task.hpp" #include "asio/system_error.hpp" #include "asio/system_executor.hpp" #include "asio/detail/push_options.hpp" namespace asio { namespace detail { template inline void promise_invoke_and_set(std::promise& p, F& f, Args&&... args) { #if !defined(ASIO_NO_EXCEPTIONS) try #endif // !defined(ASIO_NO_EXCEPTIONS) { p.set_value(f(static_cast(args)...)); } #if !defined(ASIO_NO_EXCEPTIONS) catch (...) { p.set_exception(std::current_exception()); } #endif // !defined(ASIO_NO_EXCEPTIONS) } template inline void promise_invoke_and_set(std::promise& p, F& f, Args&&... args) { #if !defined(ASIO_NO_EXCEPTIONS) try #endif // !defined(ASIO_NO_EXCEPTIONS) { f(static_cast(args)...); p.set_value(); } #if !defined(ASIO_NO_EXCEPTIONS) catch (...) { p.set_exception(std::current_exception()); } #endif // !defined(ASIO_NO_EXCEPTIONS) } // A function object adapter to invoke a nullary function object and capture // any exception thrown into a promise. template class promise_invoker { public: promise_invoker(const shared_ptr>& p, F&& f) : p_(p), f_(static_cast(f)) { } void operator()() { #if !defined(ASIO_NO_EXCEPTIONS) try #endif // !defined(ASIO_NO_EXCEPTIONS) { f_(); } #if !defined(ASIO_NO_EXCEPTIONS) catch (...) { p_->set_exception(std::current_exception()); } #endif // !defined(ASIO_NO_EXCEPTIONS) } private: shared_ptr> p_; decay_t f_; }; // An executor that adapts the system_executor to capture any exeption thrown // by a submitted function object and save it into a promise. template class promise_executor { public: explicit promise_executor(const shared_ptr>& p) : p_(p) { } execution_context& query(execution::context_t) const noexcept { return asio::query(system_executor(), execution::context); } static constexpr Blocking query(execution::blocking_t) { return Blocking(); } promise_executor require(execution::blocking_t::possibly_t) const { return promise_executor(p_); } promise_executor require(execution::blocking_t::never_t) const { return promise_executor(p_); } template void execute(F&& f) const { asio::require(system_executor(), Blocking()).execute( promise_invoker(p_, static_cast(f))); } #if !defined(ASIO_NO_TS_EXECUTORS) execution_context& context() const noexcept { return system_executor().context(); } void on_work_started() const noexcept {} void on_work_finished() const noexcept {} template void dispatch(F&& f, const A&) const { promise_invoker(p_, static_cast(f))(); } template void post(F&& f, const A& a) const { system_executor().post( promise_invoker(p_, static_cast(f)), a); } template void defer(F&& f, const A& a) const { system_executor().defer( promise_invoker(p_, static_cast(f)), a); } #endif // !defined(ASIO_NO_TS_EXECUTORS) friend bool operator==(const promise_executor& a, const promise_executor& b) noexcept { return a.p_ == b.p_; } friend bool operator!=(const promise_executor& a, const promise_executor& b) noexcept { return a.p_ != b.p_; } private: shared_ptr> p_; }; // The base class for all completion handlers that create promises. template class promise_creator { public: typedef promise_executor executor_type; executor_type get_executor() const noexcept { return executor_type(p_); } typedef std::future future_type; future_type get_future() { return p_->get_future(); } protected: template void create_promise(const Allocator& a) { ASIO_REBIND_ALLOC(Allocator, char) b(a); p_ = std::allocate_shared>(b, std::allocator_arg, b); } shared_ptr> p_; }; // For completion signature void(). class promise_handler_0 : public promise_creator { public: void operator()() { this->p_->set_value(); } }; // For completion signature void(error_code). class promise_handler_ec_0 : public promise_creator { public: void operator()(const asio::error_code& ec) { if (ec) { this->p_->set_exception( std::make_exception_ptr( asio::system_error(ec))); } else { this->p_->set_value(); } } }; // For completion signature void(exception_ptr). class promise_handler_ex_0 : public promise_creator { public: void operator()(const std::exception_ptr& ex) { if (ex) { this->p_->set_exception(ex); } else { this->p_->set_value(); } } }; // For completion signature void(T). template class promise_handler_1 : public promise_creator { public: template void operator()(Arg&& arg) { this->p_->set_value(static_cast(arg)); } }; // For completion signature void(error_code, T). template class promise_handler_ec_1 : public promise_creator { public: template void operator()(const asio::error_code& ec, Arg&& arg) { if (ec) { this->p_->set_exception( std::make_exception_ptr( asio::system_error(ec))); } else this->p_->set_value(static_cast(arg)); } }; // For completion signature void(exception_ptr, T). template class promise_handler_ex_1 : public promise_creator { public: template void operator()(const std::exception_ptr& ex, Arg&& arg) { if (ex) this->p_->set_exception(ex); else this->p_->set_value(static_cast(arg)); } }; // For completion signature void(T1, ..., Tn); template class promise_handler_n : public promise_creator { public: template void operator()(Args&&... args) { this->p_->set_value( std::forward_as_tuple( static_cast(args)...)); } }; // For completion signature void(error_code, T1, ..., Tn); template class promise_handler_ec_n : public promise_creator { public: template void operator()(const asio::error_code& ec, Args&&... args) { if (ec) { this->p_->set_exception( std::make_exception_ptr( asio::system_error(ec))); } else { this->p_->set_value( std::forward_as_tuple( static_cast(args)...)); } } }; // For completion signature void(exception_ptr, T1, ..., Tn); template class promise_handler_ex_n : public promise_creator { public: template void operator()(const std::exception_ptr& ex, Args&&... args) { if (ex) this->p_->set_exception(ex); else { this->p_->set_value( std::forward_as_tuple( static_cast(args)...)); } } }; // Helper template to choose the appropriate concrete promise handler // implementation based on the supplied completion signature. template class promise_handler_selector; template <> class promise_handler_selector : public promise_handler_0 {}; template <> class promise_handler_selector : public promise_handler_ec_0 {}; template <> class promise_handler_selector : public promise_handler_ex_0 {}; template class promise_handler_selector : public promise_handler_1 {}; template class promise_handler_selector : public promise_handler_ec_1 {}; template class promise_handler_selector : public promise_handler_ex_1 {}; template class promise_handler_selector : public promise_handler_n> {}; template class promise_handler_selector : public promise_handler_ec_n> {}; template class promise_handler_selector : public promise_handler_ex_n> {}; // Completion handlers produced from the use_future completion token, when not // using use_future::operator(). template class promise_handler : public promise_handler_selector { public: typedef Allocator allocator_type; typedef void result_type; promise_handler(use_future_t u) : allocator_(u.get_allocator()) { this->create_promise(allocator_); } allocator_type get_allocator() const noexcept { return allocator_; } private: Allocator allocator_; }; template struct promise_function_wrapper { explicit promise_function_wrapper(Function& f) : function_(static_cast(f)) { } explicit promise_function_wrapper(const Function& f) : function_(f) { } void operator()() { function_(); } Function function_; }; // Helper base class for async_result specialisation. template class promise_async_result { public: typedef promise_handler completion_handler_type; typedef typename completion_handler_type::future_type return_type; explicit promise_async_result(completion_handler_type& h) : future_(h.get_future()) { } return_type get() { return static_cast(future_); } private: return_type future_; }; // Return value from use_future::operator(). template class packaged_token { public: packaged_token(Function f, const Allocator& a) : function_(static_cast(f)), allocator_(a) { } //private: Function function_; Allocator allocator_; }; // Completion handlers produced from the use_future completion token, when // using use_future::operator(). template class packaged_handler : public promise_creator { public: typedef Allocator allocator_type; typedef void result_type; packaged_handler(packaged_token t) : function_(static_cast(t.function_)), allocator_(t.allocator_) { this->create_promise(allocator_); } allocator_type get_allocator() const noexcept { return allocator_; } template void operator()(Args&&... args) { (promise_invoke_and_set)(*this->p_, function_, static_cast(args)...); } private: Function function_; Allocator allocator_; }; // Helper base class for async_result specialisation. template class packaged_async_result { public: typedef packaged_handler completion_handler_type; typedef typename completion_handler_type::future_type return_type; explicit packaged_async_result(completion_handler_type& h) : future_(h.get_future()) { } return_type get() { return static_cast(future_); } private: return_type future_; }; } // namespace detail template template inline detail::packaged_token, Allocator> use_future_t::operator()(Function&& f) const { return detail::packaged_token, Allocator>( static_cast(f), allocator_); } #if !defined(GENERATING_DOCUMENTATION) template class async_result, Result(Args...)> : public detail::promise_async_result< void(decay_t...), Allocator> { public: explicit async_result( typename detail::promise_async_result...), Allocator>::completion_handler_type& h) : detail::promise_async_result< void(decay_t...), Allocator>(h) { } }; template class async_result, Result(Args...)> : public detail::packaged_async_result> { public: explicit async_result( typename detail::packaged_async_result>::completion_handler_type& h) : detail::packaged_async_result>(h) { } }; namespace traits { #if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template struct equality_comparable< asio::detail::promise_executor> { static constexpr bool is_valid = true; static constexpr bool is_noexcept = true; }; #endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template struct execute_member< asio::detail::promise_executor, Function> { static constexpr bool is_valid = true; static constexpr bool is_noexcept = false; typedef void result_type; }; #endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) template struct query_static_constexpr_member< asio::detail::promise_executor, Property, typename asio::enable_if< asio::is_convertible< Property, asio::execution::blocking_t >::value >::type > { static constexpr bool is_valid = true; static constexpr bool is_noexcept = true; typedef Blocking result_type; static constexpr result_type value() noexcept { return Blocking(); } }; #endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) #if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) template struct query_member< asio::detail::promise_executor, execution::context_t > { static constexpr bool is_valid = true; static constexpr bool is_noexcept = true; typedef asio::system_context& result_type; }; #endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) #if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) template struct require_member< asio::detail::promise_executor, execution::blocking_t::possibly_t > { static constexpr bool is_valid = true; static constexpr bool is_noexcept = true; typedef asio::detail::promise_executor result_type; }; template struct require_member< asio::detail::promise_executor, execution::blocking_t::never_t > { static constexpr bool is_valid = true; static constexpr bool is_noexcept = true; typedef asio::detail::promise_executor result_type; }; #endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) } // namespace traits #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio #include "asio/detail/pop_options.hpp" #endif // ASIO_IMPL_USE_FUTURE_HPP