1//
2// bind_executor.hpp
3// ~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_BIND_EXECUTOR_HPP
12#define BOOST_ASIO_BIND_EXECUTOR_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19#include <boost/asio/detail/type_traits.hpp>
20#include <boost/asio/associated_executor.hpp>
21#include <boost/asio/associator.hpp>
22#include <boost/asio/async_result.hpp>
23#include <boost/asio/execution/executor.hpp>
24#include <boost/asio/execution_context.hpp>
25#include <boost/asio/is_executor.hpp>
26#include <boost/asio/uses_executor.hpp>
27
28#include <boost/asio/detail/push_options.hpp>
29
30namespace boost {
31namespace asio {
32namespace detail {
33
34// Helper to automatically define nested typedef result_type.
35
36template <typename T, typename = void>
37struct executor_binder_result_type
38{
39protected:
40 typedef void result_type_or_void;
41};
42
43template <typename T>
44struct executor_binder_result_type<T, void_t<typename T::result_type>>
45{
46 typedef typename T::result_type result_type;
47protected:
48 typedef result_type result_type_or_void;
49};
50
51template <typename R>
52struct executor_binder_result_type<R(*)()>
53{
54 typedef R result_type;
55protected:
56 typedef result_type result_type_or_void;
57};
58
59template <typename R>
60struct executor_binder_result_type<R(&)()>
61{
62 typedef R result_type;
63protected:
64 typedef result_type result_type_or_void;
65};
66
67template <typename R, typename A1>
68struct executor_binder_result_type<R(*)(A1)>
69{
70 typedef R result_type;
71protected:
72 typedef result_type result_type_or_void;
73};
74
75template <typename R, typename A1>
76struct executor_binder_result_type<R(&)(A1)>
77{
78 typedef R result_type;
79protected:
80 typedef result_type result_type_or_void;
81};
82
83template <typename R, typename A1, typename A2>
84struct executor_binder_result_type<R(*)(A1, A2)>
85{
86 typedef R result_type;
87protected:
88 typedef result_type result_type_or_void;
89};
90
91template <typename R, typename A1, typename A2>
92struct executor_binder_result_type<R(&)(A1, A2)>
93{
94 typedef R result_type;
95protected:
96 typedef result_type result_type_or_void;
97};
98
99// Helper to automatically define nested typedef argument_type.
100
101template <typename T, typename = void>
102struct executor_binder_argument_type {};
103
104template <typename T>
105struct executor_binder_argument_type<T, void_t<typename T::argument_type>>
106{
107 typedef typename T::argument_type argument_type;
108};
109
110template <typename R, typename A1>
111struct executor_binder_argument_type<R(*)(A1)>
112{
113 typedef A1 argument_type;
114};
115
116template <typename R, typename A1>
117struct executor_binder_argument_type<R(&)(A1)>
118{
119 typedef A1 argument_type;
120};
121
122// Helper to automatically define nested typedefs first_argument_type and
123// second_argument_type.
124
125template <typename T, typename = void>
126struct executor_binder_argument_types {};
127
128template <typename T>
129struct executor_binder_argument_types<T,
130 void_t<typename T::first_argument_type>>
131{
132 typedef typename T::first_argument_type first_argument_type;
133 typedef typename T::second_argument_type second_argument_type;
134};
135
136template <typename R, typename A1, typename A2>
137struct executor_binder_argument_type<R(*)(A1, A2)>
138{
139 typedef A1 first_argument_type;
140 typedef A2 second_argument_type;
141};
142
143template <typename R, typename A1, typename A2>
144struct executor_binder_argument_type<R(&)(A1, A2)>
145{
146 typedef A1 first_argument_type;
147 typedef A2 second_argument_type;
148};
149
150// Helper to perform uses_executor construction of the target type, if
151// required.
152
153template <typename T, typename Executor, bool UsesExecutor>
154class executor_binder_base;
155
156template <typename T, typename Executor>
157class executor_binder_base<T, Executor, true>
158{
159protected:
160 template <typename E, typename U>
161 executor_binder_base(E&& e, U&& u)
162 : executor_(static_cast<E&&>(e)),
163 target_(executor_arg_t(), executor_, static_cast<U&&>(u))
164 {
165 }
166
167 Executor executor_;
168 T target_;
169};
170
171template <typename T, typename Executor>
172class executor_binder_base<T, Executor, false>
173{
174protected:
175 template <typename E, typename U>
176 executor_binder_base(E&& e, U&& u)
177 : executor_(static_cast<E&&>(e)),
178 target_(static_cast<U&&>(u))
179 {
180 }
181
182 Executor executor_;
183 T target_;
184};
185
186} // namespace detail
187
188/// A call wrapper type to bind an executor of type @c Executor to an object of
189/// type @c T.
190template <typename T, typename Executor>
191class executor_binder
192#if !defined(GENERATING_DOCUMENTATION)
193 : public detail::executor_binder_result_type<T>,
194 public detail::executor_binder_argument_type<T>,
195 public detail::executor_binder_argument_types<T>,
196 private detail::executor_binder_base<
197 T, Executor, uses_executor<T, Executor>::value>
198#endif // !defined(GENERATING_DOCUMENTATION)
199{
200public:
201 /// The type of the target object.
202 typedef T target_type;
203
204 /// The type of the associated executor.
205 typedef Executor executor_type;
206
207#if defined(GENERATING_DOCUMENTATION)
208 /// The return type if a function.
209 /**
210 * The type of @c result_type is based on the type @c T of the wrapper's
211 * target object:
212 *
213 * @li if @c T is a pointer to function type, @c result_type is a synonym for
214 * the return type of @c T;
215 *
216 * @li if @c T is a class type with a member type @c result_type, then @c
217 * result_type is a synonym for @c T::result_type;
218 *
219 * @li otherwise @c result_type is not defined.
220 */
221 typedef see_below result_type;
222
223 /// The type of the function's argument.
224 /**
225 * The type of @c argument_type is based on the type @c T of the wrapper's
226 * target object:
227 *
228 * @li if @c T is a pointer to a function type accepting a single argument,
229 * @c argument_type is a synonym for the return type of @c T;
230 *
231 * @li if @c T is a class type with a member type @c argument_type, then @c
232 * argument_type is a synonym for @c T::argument_type;
233 *
234 * @li otherwise @c argument_type is not defined.
235 */
236 typedef see_below argument_type;
237
238 /// The type of the function's first argument.
239 /**
240 * The type of @c first_argument_type is based on the type @c T of the
241 * wrapper's target object:
242 *
243 * @li if @c T is a pointer to a function type accepting two arguments, @c
244 * first_argument_type is a synonym for the return type of @c T;
245 *
246 * @li if @c T is a class type with a member type @c first_argument_type,
247 * then @c first_argument_type is a synonym for @c T::first_argument_type;
248 *
249 * @li otherwise @c first_argument_type is not defined.
250 */
251 typedef see_below first_argument_type;
252
253 /// The type of the function's second argument.
254 /**
255 * The type of @c second_argument_type is based on the type @c T of the
256 * wrapper's target object:
257 *
258 * @li if @c T is a pointer to a function type accepting two arguments, @c
259 * second_argument_type is a synonym for the return type of @c T;
260 *
261 * @li if @c T is a class type with a member type @c first_argument_type,
262 * then @c second_argument_type is a synonym for @c T::second_argument_type;
263 *
264 * @li otherwise @c second_argument_type is not defined.
265 */
266 typedef see_below second_argument_type;
267#endif // defined(GENERATING_DOCUMENTATION)
268
269 /// Construct an executor wrapper for the specified object.
270 /**
271 * This constructor is only valid if the type @c T is constructible from type
272 * @c U.
273 */
274 template <typename U>
275 executor_binder(executor_arg_t, const executor_type& e,
276 U&& u)
277 : base_type(e, static_cast<U&&>(u))
278 {
279 }
280
281 /// Copy constructor.
282 executor_binder(const executor_binder& other)
283 : base_type(other.get_executor(), other.get())
284 {
285 }
286
287 /// Construct a copy, but specify a different executor.
288 executor_binder(executor_arg_t, const executor_type& e,
289 const executor_binder& other)
290 : base_type(e, other.get())
291 {
292 }
293
294 /// Construct a copy of a different executor wrapper type.
295 /**
296 * This constructor is only valid if the @c Executor type is constructible
297 * from type @c OtherExecutor, and the type @c T is constructible from type
298 * @c U.
299 */
300 template <typename U, typename OtherExecutor>
301 executor_binder(const executor_binder<U, OtherExecutor>& other,
302 constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
303 constraint_t<is_constructible<T, U>::value> = 0)
304 : base_type(other.get_executor(), other.get())
305 {
306 }
307
308 /// Construct a copy of a different executor wrapper type, but specify a
309 /// different executor.
310 /**
311 * This constructor is only valid if the type @c T is constructible from type
312 * @c U.
313 */
314 template <typename U, typename OtherExecutor>
315 executor_binder(executor_arg_t, const executor_type& e,
316 const executor_binder<U, OtherExecutor>& other,
317 constraint_t<is_constructible<T, U>::value> = 0)
318 : base_type(e, other.get())
319 {
320 }
321
322 /// Move constructor.
323 executor_binder(executor_binder&& other)
324 : base_type(static_cast<executor_type&&>(other.get_executor()),
325 static_cast<T&&>(other.get()))
326 {
327 }
328
329 /// Move construct the target object, but specify a different executor.
330 executor_binder(executor_arg_t, const executor_type& e,
331 executor_binder&& other)
332 : base_type(e, static_cast<T&&>(other.get()))
333 {
334 }
335
336 /// Move construct from a different executor wrapper type.
337 template <typename U, typename OtherExecutor>
338 executor_binder(executor_binder<U, OtherExecutor>&& other,
339 constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
340 constraint_t<is_constructible<T, U>::value> = 0)
341 : base_type(static_cast<OtherExecutor&&>(other.get_executor()),
342 static_cast<U&&>(other.get()))
343 {
344 }
345
346 /// Move construct from a different executor wrapper type, but specify a
347 /// different executor.
348 template <typename U, typename OtherExecutor>
349 executor_binder(executor_arg_t, const executor_type& e,
350 executor_binder<U, OtherExecutor>&& other,
351 constraint_t<is_constructible<T, U>::value> = 0)
352 : base_type(e, static_cast<U&&>(other.get()))
353 {
354 }
355
356 /// Destructor.
357 ~executor_binder()
358 {
359 }
360
361 /// Obtain a reference to the target object.
362 target_type& get() noexcept
363 {
364 return this->target_;
365 }
366
367 /// Obtain a reference to the target object.
368 const target_type& get() const noexcept
369 {
370 return this->target_;
371 }
372
373 /// Obtain the associated executor.
374 executor_type get_executor() const noexcept
375 {
376 return this->executor_;
377 }
378
379 /// Forwarding function call operator.
380 template <typename... Args>
381 result_of_t<T(Args...)> operator()(Args&&... args)
382 {
383 return this->target_(static_cast<Args&&>(args)...);
384 }
385
386 /// Forwarding function call operator.
387 template <typename... Args>
388 result_of_t<T(Args...)> operator()(Args&&... args) const
389 {
390 return this->target_(static_cast<Args&&>(args)...);
391 }
392
393private:
394 typedef detail::executor_binder_base<T, Executor,
395 uses_executor<T, Executor>::value> base_type;
396};
397
398/// Associate an object of type @c T with an executor of type @c Executor.
399template <typename Executor, typename T>
400BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>, Executor>
401bind_executor(const Executor& ex, T&& t,
402 constraint_t<
403 is_executor<Executor>::value || execution::is_executor<Executor>::value
404 > = 0)
405{
406 return executor_binder<decay_t<T>, Executor>(
407 executor_arg_t(), ex, static_cast<T&&>(t));
408}
409
410/// Associate an object of type @c T with an execution context's executor.
411template <typename ExecutionContext, typename T>
412BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>,
413 typename ExecutionContext::executor_type>
414bind_executor(ExecutionContext& ctx, T&& t,
415 constraint_t<
416 is_convertible<ExecutionContext&, execution_context&>::value
417 > = 0)
418{
419 return executor_binder<decay_t<T>, typename ExecutionContext::executor_type>(
420 executor_arg_t(), ctx.get_executor(), static_cast<T&&>(t));
421}
422
423#if !defined(GENERATING_DOCUMENTATION)
424
425template <typename T, typename Executor>
426struct uses_executor<executor_binder<T, Executor>, Executor>
427 : true_type {};
428
429namespace detail {
430
431template <typename TargetAsyncResult, typename Executor, typename = void>
432class executor_binder_completion_handler_async_result
433{
434public:
435 template <typename T>
436 explicit executor_binder_completion_handler_async_result(T&)
437 {
438 }
439};
440
441template <typename TargetAsyncResult, typename Executor>
442class executor_binder_completion_handler_async_result<
443 TargetAsyncResult, Executor,
444 void_t<typename TargetAsyncResult::completion_handler_type >>
445{
446private:
447 TargetAsyncResult target_;
448
449public:
450 typedef executor_binder<
451 typename TargetAsyncResult::completion_handler_type, Executor>
452 completion_handler_type;
453
454 explicit executor_binder_completion_handler_async_result(
455 typename TargetAsyncResult::completion_handler_type& handler)
456 : target_(handler)
457 {
458 }
459
460 auto get() -> decltype(target_.get())
461 {
462 return target_.get();
463 }
464};
465
466template <typename TargetAsyncResult, typename = void>
467struct executor_binder_async_result_return_type
468{
469};
470
471template <typename TargetAsyncResult>
472struct executor_binder_async_result_return_type<TargetAsyncResult,
473 void_t<typename TargetAsyncResult::return_type>>
474{
475 typedef typename TargetAsyncResult::return_type return_type;
476};
477
478} // namespace detail
479
480template <typename T, typename Executor, typename Signature>
481class async_result<executor_binder<T, Executor>, Signature> :
482 public detail::executor_binder_completion_handler_async_result<
483 async_result<T, Signature>, Executor>,
484 public detail::executor_binder_async_result_return_type<
485 async_result<T, Signature>>
486{
487public:
488 explicit async_result(executor_binder<T, Executor>& b)
489 : detail::executor_binder_completion_handler_async_result<
490 async_result<T, Signature>, Executor>(b.get())
491 {
492 }
493
494 template <typename Initiation>
495 struct init_wrapper
496 {
497 template <typename Init>
498 init_wrapper(const Executor& ex, Init&& init)
499 : ex_(ex),
500 initiation_(static_cast<Init&&>(init))
501 {
502 }
503
504 template <typename Handler, typename... Args>
505 void operator()(Handler&& handler, Args&&... args)
506 {
507 static_cast<Initiation&&>(initiation_)(
508 executor_binder<decay_t<Handler>, Executor>(
509 executor_arg_t(), ex_, static_cast<Handler&&>(handler)),
510 static_cast<Args&&>(args)...);
511 }
512
513 template <typename Handler, typename... Args>
514 void operator()(Handler&& handler, Args&&... args) const
515 {
516 initiation_(
517 executor_binder<decay_t<Handler>, Executor>(
518 executor_arg_t(), ex_, static_cast<Handler&&>(handler)),
519 static_cast<Args&&>(args)...);
520 }
521
522 Executor ex_;
523 Initiation initiation_;
524 };
525
526 template <typename Initiation, typename RawCompletionToken, typename... Args>
527 static auto initiate(Initiation&& initiation,
528 RawCompletionToken&& token, Args&&... args)
529 -> decltype(
530 async_initiate<T, Signature>(
531 declval<init_wrapper<decay_t<Initiation>>>(),
532 token.get(), static_cast<Args&&>(args)...))
533 {
534 return async_initiate<T, Signature>(
535 init_wrapper<decay_t<Initiation>>(
536 token.get_executor(), static_cast<Initiation&&>(initiation)),
537 token.get(), static_cast<Args&&>(args)...);
538 }
539
540private:
541 async_result(const async_result&) = delete;
542 async_result& operator=(const async_result&) = delete;
543};
544
545template <template <typename, typename> class Associator,
546 typename T, typename Executor, typename DefaultCandidate>
547struct associator<Associator, executor_binder<T, Executor>, DefaultCandidate>
548 : Associator<T, DefaultCandidate>
549{
550 static typename Associator<T, DefaultCandidate>::type get(
551 const executor_binder<T, Executor>& b) noexcept
552 {
553 return Associator<T, DefaultCandidate>::get(b.get());
554 }
555
556 static auto get(const executor_binder<T, Executor>& b,
557 const DefaultCandidate& c) noexcept
558 -> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
559 {
560 return Associator<T, DefaultCandidate>::get(b.get(), c);
561 }
562};
563
564template <typename T, typename Executor, typename Executor1>
565struct associated_executor<executor_binder<T, Executor>, Executor1>
566{
567 typedef Executor type;
568
569 static auto get(const executor_binder<T, Executor>& b,
570 const Executor1& = Executor1()) noexcept
571 -> decltype(b.get_executor())
572 {
573 return b.get_executor();
574 }
575};
576
577#endif // !defined(GENERATING_DOCUMENTATION)
578
579} // namespace asio
580} // namespace boost
581
582#include <boost/asio/detail/pop_options.hpp>
583
584#endif // BOOST_ASIO_BIND_EXECUTOR_HPP
585

source code of boost/libs/asio/include/boost/asio/bind_executor.hpp