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 | |
30 | namespace boost { |
31 | namespace asio { |
32 | namespace detail { |
33 | |
34 | // Helper to automatically define nested typedef result_type. |
35 | |
36 | template <typename T, typename = void> |
37 | struct executor_binder_result_type |
38 | { |
39 | protected: |
40 | typedef void result_type_or_void; |
41 | }; |
42 | |
43 | template <typename T> |
44 | struct executor_binder_result_type<T, void_t<typename T::result_type>> |
45 | { |
46 | typedef typename T::result_type result_type; |
47 | protected: |
48 | typedef result_type result_type_or_void; |
49 | }; |
50 | |
51 | template <typename R> |
52 | struct executor_binder_result_type<R(*)()> |
53 | { |
54 | typedef R result_type; |
55 | protected: |
56 | typedef result_type result_type_or_void; |
57 | }; |
58 | |
59 | template <typename R> |
60 | struct executor_binder_result_type<R(&)()> |
61 | { |
62 | typedef R result_type; |
63 | protected: |
64 | typedef result_type result_type_or_void; |
65 | }; |
66 | |
67 | template <typename R, typename A1> |
68 | struct executor_binder_result_type<R(*)(A1)> |
69 | { |
70 | typedef R result_type; |
71 | protected: |
72 | typedef result_type result_type_or_void; |
73 | }; |
74 | |
75 | template <typename R, typename A1> |
76 | struct executor_binder_result_type<R(&)(A1)> |
77 | { |
78 | typedef R result_type; |
79 | protected: |
80 | typedef result_type result_type_or_void; |
81 | }; |
82 | |
83 | template <typename R, typename A1, typename A2> |
84 | struct executor_binder_result_type<R(*)(A1, A2)> |
85 | { |
86 | typedef R result_type; |
87 | protected: |
88 | typedef result_type result_type_or_void; |
89 | }; |
90 | |
91 | template <typename R, typename A1, typename A2> |
92 | struct executor_binder_result_type<R(&)(A1, A2)> |
93 | { |
94 | typedef R result_type; |
95 | protected: |
96 | typedef result_type result_type_or_void; |
97 | }; |
98 | |
99 | // Helper to automatically define nested typedef argument_type. |
100 | |
101 | template <typename T, typename = void> |
102 | struct executor_binder_argument_type {}; |
103 | |
104 | template <typename T> |
105 | struct executor_binder_argument_type<T, void_t<typename T::argument_type>> |
106 | { |
107 | typedef typename T::argument_type argument_type; |
108 | }; |
109 | |
110 | template <typename R, typename A1> |
111 | struct executor_binder_argument_type<R(*)(A1)> |
112 | { |
113 | typedef A1 argument_type; |
114 | }; |
115 | |
116 | template <typename R, typename A1> |
117 | struct 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 | |
125 | template <typename T, typename = void> |
126 | struct executor_binder_argument_types {}; |
127 | |
128 | template <typename T> |
129 | struct 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 | |
136 | template <typename R, typename A1, typename A2> |
137 | struct executor_binder_argument_type<R(*)(A1, A2)> |
138 | { |
139 | typedef A1 first_argument_type; |
140 | typedef A2 second_argument_type; |
141 | }; |
142 | |
143 | template <typename R, typename A1, typename A2> |
144 | struct 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 | |
153 | template <typename T, typename Executor, bool UsesExecutor> |
154 | class executor_binder_base; |
155 | |
156 | template <typename T, typename Executor> |
157 | class executor_binder_base<T, Executor, true> |
158 | { |
159 | protected: |
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 | |
171 | template <typename T, typename Executor> |
172 | class executor_binder_base<T, Executor, false> |
173 | { |
174 | protected: |
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. |
190 | template <typename T, typename Executor> |
191 | class 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 | { |
200 | public: |
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 | |
393 | private: |
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. |
399 | template <typename Executor, typename T> |
400 | BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>, Executor> |
401 | bind_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. |
411 | template <typename ExecutionContext, typename T> |
412 | BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>, |
413 | typename ExecutionContext::executor_type> |
414 | bind_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 | |
425 | template <typename T, typename Executor> |
426 | struct uses_executor<executor_binder<T, Executor>, Executor> |
427 | : true_type {}; |
428 | |
429 | namespace detail { |
430 | |
431 | template <typename TargetAsyncResult, typename Executor, typename = void> |
432 | class executor_binder_completion_handler_async_result |
433 | { |
434 | public: |
435 | template <typename T> |
436 | explicit executor_binder_completion_handler_async_result(T&) |
437 | { |
438 | } |
439 | }; |
440 | |
441 | template <typename TargetAsyncResult, typename Executor> |
442 | class executor_binder_completion_handler_async_result< |
443 | TargetAsyncResult, Executor, |
444 | void_t<typename TargetAsyncResult::completion_handler_type >> |
445 | { |
446 | private: |
447 | TargetAsyncResult target_; |
448 | |
449 | public: |
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 | |
466 | template <typename TargetAsyncResult, typename = void> |
467 | struct executor_binder_async_result_return_type |
468 | { |
469 | }; |
470 | |
471 | template <typename TargetAsyncResult> |
472 | struct 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 | |
480 | template <typename T, typename Executor, typename Signature> |
481 | class 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 | { |
487 | public: |
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 | |
540 | private: |
541 | async_result(const async_result&) = delete; |
542 | async_result& operator=(const async_result&) = delete; |
543 | }; |
544 | |
545 | template <template <typename, typename> class Associator, |
546 | typename T, typename Executor, typename DefaultCandidate> |
547 | struct 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 | |
564 | template <typename T, typename Executor, typename Executor1> |
565 | struct 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 | |