From 85535cec190106111e89a459b87f78322bcf959e Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Wed, 26 Jun 2024 22:43:11 +1000 Subject: [PATCH] Allow bind_executor to be used as a partial completion token. --- include/boost/asio/bind_executor.hpp | 104 +++++++++++++++++++++++++-- test/bind_executor.cpp | 48 +++++++++---- 2 files changed, 136 insertions(+), 16 deletions(-) diff --git a/include/boost/asio/bind_executor.hpp b/include/boost/asio/bind_executor.hpp index b38d2c89..fbfcf81f 100644 --- a/include/boost/asio/bind_executor.hpp +++ b/include/boost/asio/bind_executor.hpp @@ -395,6 +395,49 @@ private: uses_executor::value> base_type; }; +/// A function object type that adapts a @ref completion_token to specify that +/// the completion handler should have the supplied executor as its associated +/// executor. +/** + * May also be used directly as a completion token, in which case it adapts the + * asynchronous operation's default completion token (or boost::asio::deferred + * if no default is available). + */ +template +struct partial_executor_binder +{ + /// Constructor that specifies associated executor. + explicit partial_executor_binder(const Executor& ex) + : executor_(ex) + { + } + + /// Adapt a @ref completion_token to specify that the completion handler + /// should have the executor as its associated executor. + template + BOOST_ASIO_NODISCARD inline + constexpr executor_binder, Executor> + operator()(CompletionToken&& completion_token) const + { + return executor_binder, Executor>(executor_arg_t(), + static_cast(completion_token), executor_); + } + +//private: + Executor executor_; +}; + +/// Create a partial completion token that associates an executor. +template +BOOST_ASIO_NODISCARD inline partial_executor_binder +bind_executor(const Executor& ex, + constraint_t< + is_executor::value || execution::is_executor::value + > = 0) +{ + return partial_executor_binder(ex); +} + /// Associate an object of type @c T with an executor of type @c Executor. template BOOST_ASIO_NODISCARD inline executor_binder, Executor> @@ -407,6 +450,20 @@ bind_executor(const Executor& ex, T&& t, executor_arg_t(), ex, static_cast(t)); } +/// Create a partial completion token that associates an execution context's +/// executor. +template +BOOST_ASIO_NODISCARD inline partial_executor_binder< + typename ExecutionContext::executor_type> +bind_executor(ExecutionContext& ctx, + constraint_t< + is_convertible::value + > = 0) +{ + return partial_executor_binder( + ctx.get_executor()); +} + /// Associate an object of type @c T with an execution context's executor. template BOOST_ASIO_NODISCARD inline executor_binder, @@ -527,11 +584,17 @@ public: static auto initiate(Initiation&& initiation, RawCompletionToken&& token, Args&&... args) -> decltype( - async_initiate( - declval>>(), - token.get(), static_cast(args)...)) + async_initiate< + conditional_t< + is_const>::value, const T, T>, + Signature>( + declval>>(), + token.get(), static_cast(args)...)) { - return async_initiate( + return async_initiate< + conditional_t< + is_const>::value, const T, T>, + Signature>( init_wrapper>( token.get_executor(), static_cast(initiation)), token.get(), static_cast(args)...); @@ -542,6 +605,39 @@ private: async_result& operator=(const async_result&) = delete; }; +template +struct async_result, Signatures...> +{ + template + static auto initiate(Initiation&& initiation, + RawCompletionToken&& token, Args&&... args) + -> decltype( + async_initiate< + const executor_binder< + default_completion_token_t>, + Executor>&, + Signatures...>( + static_cast(initiation), + executor_binder< + default_completion_token_t>, + Executor>(executor_arg_t(), token.executor_, + default_completion_token_t>{}), + static_cast(args)...)) + { + return async_initiate< + const executor_binder< + default_completion_token_t>, + Executor>&, + Signatures...>( + static_cast(initiation), + executor_binder< + default_completion_token_t>, + Executor>(executor_arg_t(), token.executor_, + default_completion_token_t>{}), + static_cast(args)...); + } +}; + template