diff options
Diffstat (limited to '3rdparty/asio/include/asio/detail/handler_work.hpp')
-rw-r--r-- | 3rdparty/asio/include/asio/detail/handler_work.hpp | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/3rdparty/asio/include/asio/detail/handler_work.hpp b/3rdparty/asio/include/asio/detail/handler_work.hpp new file mode 100644 index 00000000000..596d076327a --- /dev/null +++ b/3rdparty/asio/include/asio/detail/handler_work.hpp @@ -0,0 +1,511 @@ +// +// detail/handler_work.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_DETAIL_HANDLER_WORK_HPP +#define ASIO_DETAIL_HANDLER_WORK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/config.hpp" +#include "asio/associated_allocator.hpp" +#include "asio/associated_executor.hpp" +#include "asio/associated_immediate_executor.hpp" +#include "asio/detail/initiate_dispatch.hpp" +#include "asio/detail/type_traits.hpp" +#include "asio/detail/work_dispatcher.hpp" +#include "asio/execution/allocator.hpp" +#include "asio/execution/blocking.hpp" +#include "asio/execution/executor.hpp" +#include "asio/execution/outstanding_work.hpp" +#include "asio/executor_work_guard.hpp" +#include "asio/prefer.hpp" + +#include "asio/detail/push_options.hpp" + +namespace asio { + +class executor; +class io_context; + +#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +class any_completion_executor; +class any_io_executor; + +#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +namespace execution { + +template <typename...> class any_executor; + +} // namespace execution +namespace detail { + +template <typename Executor, typename CandidateExecutor = void, + typename IoContext = io_context, + typename PolymorphicExecutor = executor, typename = void> +class handler_work_base +{ +public: + explicit handler_work_base(int, int, const Executor& ex) noexcept + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const OtherExecutor& /*candidate*/) noexcept + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + handler_work_base(const handler_work_base& other) noexcept + : executor_(other.executor_) + { + } + + handler_work_base(handler_work_base&& other) noexcept + : executor_(static_cast<executor_type&&>(other.executor_)) + { + } + + bool owns_work() const noexcept + { + return true; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) + { + asio::prefer(executor_, + execution::allocator((get_associated_allocator)(handler)) + ).execute(static_cast<Function&&>(function)); + } + +private: + typedef decay_t< + prefer_result_t<Executor, execution::outstanding_work_t::tracked_t> + > executor_type; + + executor_type executor_; +}; + +template <typename Executor, typename CandidateExecutor, + typename IoContext, typename PolymorphicExecutor> +class handler_work_base<Executor, CandidateExecutor, + IoContext, PolymorphicExecutor, + enable_if_t< + !execution::is_executor<Executor>::value + && (!is_same<Executor, PolymorphicExecutor>::value + || !is_same<CandidateExecutor, void>::value) + > + > +{ +public: + explicit handler_work_base(int, int, const Executor& ex) noexcept + : executor_(ex), + owns_work_(true) + { + executor_.on_work_started(); + } + + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const Executor& candidate) noexcept + : executor_(ex), + owns_work_(ex != candidate) + { + if (owns_work_) + executor_.on_work_started(); + } + + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const OtherExecutor& /*candidate*/) noexcept + : executor_(ex), + owns_work_(true) + { + executor_.on_work_started(); + } + + handler_work_base(const handler_work_base& other) noexcept + : executor_(other.executor_), + owns_work_(other.owns_work_) + { + if (owns_work_) + executor_.on_work_started(); + } + + handler_work_base(handler_work_base&& other) noexcept + : executor_(static_cast<Executor&&>(other.executor_)), + owns_work_(other.owns_work_) + { + other.owns_work_ = false; + } + + ~handler_work_base() + { + if (owns_work_) + executor_.on_work_finished(); + } + + bool owns_work() const noexcept + { + return owns_work_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) + { + executor_.dispatch(static_cast<Function&&>(function), + asio::get_associated_allocator(handler)); + } + +private: + Executor executor_; + bool owns_work_; +}; + +template <typename Executor, typename IoContext, typename PolymorphicExecutor> +class handler_work_base<Executor, void, IoContext, PolymorphicExecutor, + enable_if_t< + is_same< + Executor, + typename IoContext::executor_type + >::value + > + > +{ +public: + explicit handler_work_base(int, int, const Executor&) + { + } + + bool owns_work() const noexcept + { + return false; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler&) + { + // When using a native implementation, I/O completion handlers are + // already dispatched according to the execution context's executor's + // rules. We can call the function directly. + static_cast<Function&&>(function)(); + } +}; + +template <typename Executor, typename IoContext> +class handler_work_base<Executor, void, IoContext, Executor> +{ +public: + explicit handler_work_base(int, int, const Executor& ex) noexcept +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? Executor() : ex) +#else // !defined(ASIO_NO_TYPEID) + : executor_(ex) +#endif // !defined(ASIO_NO_TYPEID) + { + if (executor_) + executor_.on_work_started(); + } + + handler_work_base(bool /*base1_owns_work*/, const Executor& ex, + const Executor& candidate) noexcept + : executor_(ex != candidate ? ex : Executor()) + { + if (executor_) + executor_.on_work_started(); + } + + template <typename OtherExecutor> + handler_work_base(const Executor& ex, + const OtherExecutor&) noexcept + : executor_(ex) + { + executor_.on_work_started(); + } + + handler_work_base(const handler_work_base& other) noexcept + : executor_(other.executor_) + { + if (executor_) + executor_.on_work_started(); + } + + handler_work_base(handler_work_base&& other) noexcept + : executor_(static_cast<Executor&&>(other.executor_)) + { + } + + ~handler_work_base() + { + if (executor_) + executor_.on_work_finished(); + } + + bool owns_work() const noexcept + { + return !!executor_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler& handler) + { + executor_.dispatch(static_cast<Function&&>(function), + asio::get_associated_allocator(handler)); + } + +private: + Executor executor_; +}; + +template <typename... SupportableProperties, typename CandidateExecutor, + typename IoContext, typename PolymorphicExecutor> +class handler_work_base<execution::any_executor<SupportableProperties...>, + CandidateExecutor, IoContext, PolymorphicExecutor> +{ +public: + typedef execution::any_executor<SupportableProperties...> executor_type; + + explicit handler_work_base(int, int, const executor_type& ex) noexcept +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) +#else // !defined(ASIO_NO_TYPEID) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) +#endif // !defined(ASIO_NO_TYPEID) + { + } + + handler_work_base(bool base1_owns_work, const executor_type& ex, + const executor_type& candidate) noexcept + : executor_( + !base1_owns_work && ex == candidate + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const executor_type& ex, + const OtherExecutor& /*candidate*/) noexcept + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + handler_work_base(const handler_work_base& other) noexcept + : executor_(other.executor_) + { + } + + handler_work_base(handler_work_base&& other) noexcept + : executor_(static_cast<executor_type&&>(other.executor_)) + { + } + + bool owns_work() const noexcept + { + return !!executor_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler&) + { + executor_.execute(static_cast<Function&&>(function)); + } + +private: + executor_type executor_; +}; + +#if !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +template <typename Executor, typename CandidateExecutor, + typename IoContext, typename PolymorphicExecutor> +class handler_work_base< + Executor, CandidateExecutor, + IoContext, PolymorphicExecutor, + enable_if_t< + is_same<Executor, any_completion_executor>::value + || is_same<Executor, any_io_executor>::value + > + > +{ +public: + typedef Executor executor_type; + + explicit handler_work_base(int, int, + const executor_type& ex) noexcept +#if !defined(ASIO_NO_TYPEID) + : executor_( + ex.target_type() == typeid(typename IoContext::executor_type) + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) +#else // !defined(ASIO_NO_TYPEID) + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) +#endif // !defined(ASIO_NO_TYPEID) + { + } + + handler_work_base(bool base1_owns_work, const executor_type& ex, + const executor_type& candidate) noexcept + : executor_( + !base1_owns_work && ex == candidate + ? executor_type() + : asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + template <typename OtherExecutor> + handler_work_base(bool /*base1_owns_work*/, const executor_type& ex, + const OtherExecutor& /*candidate*/) noexcept + : executor_(asio::prefer(ex, execution::outstanding_work.tracked)) + { + } + + handler_work_base(const handler_work_base& other) noexcept + : executor_(other.executor_) + { + } + + handler_work_base(handler_work_base&& other) noexcept + : executor_(static_cast<executor_type&&>(other.executor_)) + { + } + + bool owns_work() const noexcept + { + return !!executor_; + } + + template <typename Function, typename Handler> + void dispatch(Function& function, Handler&) + { + executor_.execute(static_cast<Function&&>(function)); + } + +private: + executor_type executor_; +}; + +#endif // !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + +template <typename Handler, typename IoExecutor, typename = void> +class handler_work : + handler_work_base<IoExecutor>, + handler_work_base<associated_executor_t<Handler, IoExecutor>, IoExecutor> +{ +public: + typedef handler_work_base<IoExecutor> base1_type; + typedef handler_work_base<associated_executor_t<Handler, IoExecutor>, + IoExecutor> base2_type; + + handler_work(Handler& handler, const IoExecutor& io_ex) noexcept + : base1_type(0, 0, io_ex), + base2_type(base1_type::owns_work(), + asio::get_associated_executor(handler, io_ex), io_ex) + { + } + + template <typename Function> + void complete(Function& function, Handler& handler) + { + if (!base1_type::owns_work() && !base2_type::owns_work()) + { + // When using a native implementation, I/O completion handlers are + // already dispatched according to the execution context's executor's + // rules. We can call the function directly. + static_cast<Function&&>(function)(); + } + else + { + base2_type::dispatch(function, handler); + } + } +}; + +template <typename Handler, typename IoExecutor> +class handler_work< + Handler, IoExecutor, + enable_if_t< + is_same< + typename associated_executor<Handler, + IoExecutor>::asio_associated_executor_is_unspecialised, + void + >::value + > + > : handler_work_base<IoExecutor> +{ +public: + typedef handler_work_base<IoExecutor> base1_type; + + handler_work(Handler&, const IoExecutor& io_ex) noexcept + : base1_type(0, 0, io_ex) + { + } + + template <typename Function> + void complete(Function& function, Handler& handler) + { + if (!base1_type::owns_work()) + { + // When using a native implementation, I/O completion handlers are + // already dispatched according to the execution context's executor's + // rules. We can call the function directly. + static_cast<Function&&>(function)(); + } + else + { + base1_type::dispatch(function, handler); + } + } +}; + +template <typename Handler, typename IoExecutor> +class immediate_handler_work +{ +public: + typedef handler_work<Handler, IoExecutor> handler_work_type; + + explicit immediate_handler_work(handler_work_type&& w) + : handler_work_(static_cast<handler_work_type&&>(w)) + { + } + + template <typename Function> + void complete(Function& function, Handler& handler, const void* io_ex) + { + typedef associated_immediate_executor_t<Handler, IoExecutor> + immediate_ex_type; + + immediate_ex_type immediate_ex = (get_associated_immediate_executor)( + handler, *static_cast<const IoExecutor*>(io_ex)); + + (initiate_dispatch_with_executor<immediate_ex_type>(immediate_ex))( + static_cast<Function&&>(function)); + } + +private: + handler_work_type handler_work_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_WORK_HPP |