File indexing completed on 2025-12-15 09:44:13
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_BIND_EXECUTOR_HPP
0012 #define BOOST_ASIO_BIND_EXECUTOR_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/asio/detail/config.hpp>
0019 #include <boost/asio/associated_executor.hpp>
0020 #include <boost/asio/associator.hpp>
0021 #include <boost/asio/async_result.hpp>
0022 #include <boost/asio/detail/initiation_base.hpp>
0023 #include <boost/asio/detail/type_traits.hpp>
0024 #include <boost/asio/execution/executor.hpp>
0025 #include <boost/asio/execution_context.hpp>
0026 #include <boost/asio/is_executor.hpp>
0027 #include <boost/asio/uses_executor.hpp>
0028
0029 #include <boost/asio/detail/push_options.hpp>
0030
0031 namespace boost {
0032 namespace asio {
0033 namespace detail {
0034
0035
0036
0037 template <typename T, typename = void>
0038 struct executor_binder_result_type
0039 {
0040 protected:
0041 typedef void result_type_or_void;
0042 };
0043
0044 template <typename T>
0045 struct executor_binder_result_type<T, void_t<typename T::result_type>>
0046 {
0047 typedef typename T::result_type result_type;
0048 protected:
0049 typedef result_type result_type_or_void;
0050 };
0051
0052 template <typename R>
0053 struct executor_binder_result_type<R(*)()>
0054 {
0055 typedef R result_type;
0056 protected:
0057 typedef result_type result_type_or_void;
0058 };
0059
0060 template <typename R>
0061 struct executor_binder_result_type<R(&)()>
0062 {
0063 typedef R result_type;
0064 protected:
0065 typedef result_type result_type_or_void;
0066 };
0067
0068 template <typename R, typename A1>
0069 struct executor_binder_result_type<R(*)(A1)>
0070 {
0071 typedef R result_type;
0072 protected:
0073 typedef result_type result_type_or_void;
0074 };
0075
0076 template <typename R, typename A1>
0077 struct executor_binder_result_type<R(&)(A1)>
0078 {
0079 typedef R result_type;
0080 protected:
0081 typedef result_type result_type_or_void;
0082 };
0083
0084 template <typename R, typename A1, typename A2>
0085 struct executor_binder_result_type<R(*)(A1, A2)>
0086 {
0087 typedef R result_type;
0088 protected:
0089 typedef result_type result_type_or_void;
0090 };
0091
0092 template <typename R, typename A1, typename A2>
0093 struct executor_binder_result_type<R(&)(A1, A2)>
0094 {
0095 typedef R result_type;
0096 protected:
0097 typedef result_type result_type_or_void;
0098 };
0099
0100
0101
0102 template <typename T, typename = void>
0103 struct executor_binder_argument_type {};
0104
0105 template <typename T>
0106 struct executor_binder_argument_type<T, void_t<typename T::argument_type>>
0107 {
0108 typedef typename T::argument_type argument_type;
0109 };
0110
0111 template <typename R, typename A1>
0112 struct executor_binder_argument_type<R(*)(A1)>
0113 {
0114 typedef A1 argument_type;
0115 };
0116
0117 template <typename R, typename A1>
0118 struct executor_binder_argument_type<R(&)(A1)>
0119 {
0120 typedef A1 argument_type;
0121 };
0122
0123
0124
0125
0126 template <typename T, typename = void>
0127 struct executor_binder_argument_types {};
0128
0129 template <typename T>
0130 struct executor_binder_argument_types<T,
0131 void_t<typename T::first_argument_type>>
0132 {
0133 typedef typename T::first_argument_type first_argument_type;
0134 typedef typename T::second_argument_type second_argument_type;
0135 };
0136
0137 template <typename R, typename A1, typename A2>
0138 struct executor_binder_argument_type<R(*)(A1, A2)>
0139 {
0140 typedef A1 first_argument_type;
0141 typedef A2 second_argument_type;
0142 };
0143
0144 template <typename R, typename A1, typename A2>
0145 struct executor_binder_argument_type<R(&)(A1, A2)>
0146 {
0147 typedef A1 first_argument_type;
0148 typedef A2 second_argument_type;
0149 };
0150
0151
0152
0153
0154 template <typename T, typename Executor, bool UsesExecutor>
0155 class executor_binder_base;
0156
0157 template <typename T, typename Executor>
0158 class executor_binder_base<T, Executor, true>
0159 {
0160 protected:
0161 template <typename E, typename U>
0162 executor_binder_base(E&& e, U&& u)
0163 : executor_(static_cast<E&&>(e)),
0164 target_(executor_arg_t(), executor_, static_cast<U&&>(u))
0165 {
0166 }
0167
0168 Executor executor_;
0169 T target_;
0170 };
0171
0172 template <typename T, typename Executor>
0173 class executor_binder_base<T, Executor, false>
0174 {
0175 protected:
0176 template <typename E, typename U>
0177 executor_binder_base(E&& e, U&& u)
0178 : executor_(static_cast<E&&>(e)),
0179 target_(static_cast<U&&>(u))
0180 {
0181 }
0182
0183 Executor executor_;
0184 T target_;
0185 };
0186
0187 }
0188
0189
0190
0191 template <typename T, typename Executor>
0192 class executor_binder
0193 #if !defined(GENERATING_DOCUMENTATION)
0194 : public detail::executor_binder_result_type<T>,
0195 public detail::executor_binder_argument_type<T>,
0196 public detail::executor_binder_argument_types<T>,
0197 private detail::executor_binder_base<
0198 T, Executor, uses_executor<T, Executor>::value>
0199 #endif
0200 {
0201 public:
0202
0203 typedef T target_type;
0204
0205
0206 typedef Executor executor_type;
0207
0208 #if defined(GENERATING_DOCUMENTATION)
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222 typedef see_below result_type;
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237 typedef see_below argument_type;
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252 typedef see_below first_argument_type;
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267 typedef see_below second_argument_type;
0268 #endif
0269
0270
0271
0272
0273
0274
0275 template <typename U>
0276 executor_binder(executor_arg_t, const executor_type& e,
0277 U&& u)
0278 : base_type(e, static_cast<U&&>(u))
0279 {
0280 }
0281
0282
0283 executor_binder(const executor_binder& other)
0284 : base_type(other.get_executor(), other.get())
0285 {
0286 }
0287
0288
0289 executor_binder(executor_arg_t, const executor_type& e,
0290 const executor_binder& other)
0291 : base_type(e, other.get())
0292 {
0293 }
0294
0295
0296
0297
0298
0299
0300
0301 template <typename U, typename OtherExecutor>
0302 executor_binder(const executor_binder<U, OtherExecutor>& other,
0303 constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
0304 constraint_t<is_constructible<T, U>::value> = 0)
0305 : base_type(other.get_executor(), other.get())
0306 {
0307 }
0308
0309
0310
0311
0312
0313
0314
0315 template <typename U, typename OtherExecutor>
0316 executor_binder(executor_arg_t, const executor_type& e,
0317 const executor_binder<U, OtherExecutor>& other,
0318 constraint_t<is_constructible<T, U>::value> = 0)
0319 : base_type(e, other.get())
0320 {
0321 }
0322
0323
0324 executor_binder(executor_binder&& other)
0325 : base_type(static_cast<executor_type&&>(other.get_executor()),
0326 static_cast<T&&>(other.get()))
0327 {
0328 }
0329
0330
0331 executor_binder(executor_arg_t, const executor_type& e,
0332 executor_binder&& other)
0333 : base_type(e, static_cast<T&&>(other.get()))
0334 {
0335 }
0336
0337
0338 template <typename U, typename OtherExecutor>
0339 executor_binder(executor_binder<U, OtherExecutor>&& other,
0340 constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
0341 constraint_t<is_constructible<T, U>::value> = 0)
0342 : base_type(static_cast<OtherExecutor&&>(other.get_executor()),
0343 static_cast<U&&>(other.get()))
0344 {
0345 }
0346
0347
0348
0349 template <typename U, typename OtherExecutor>
0350 executor_binder(executor_arg_t, const executor_type& e,
0351 executor_binder<U, OtherExecutor>&& other,
0352 constraint_t<is_constructible<T, U>::value> = 0)
0353 : base_type(e, static_cast<U&&>(other.get()))
0354 {
0355 }
0356
0357
0358 ~executor_binder()
0359 {
0360 }
0361
0362
0363 target_type& get() noexcept
0364 {
0365 return this->target_;
0366 }
0367
0368
0369 const target_type& get() const noexcept
0370 {
0371 return this->target_;
0372 }
0373
0374
0375 executor_type get_executor() const noexcept
0376 {
0377 return this->executor_;
0378 }
0379
0380
0381 template <typename... Args>
0382 result_of_t<T(Args...)> operator()(Args&&... args) &
0383 {
0384 return this->target_(static_cast<Args&&>(args)...);
0385 }
0386
0387
0388 template <typename... Args>
0389 result_of_t<T(Args...)> operator()(Args&&... args) &&
0390 {
0391 return static_cast<T&&>(this->target_)(static_cast<Args&&>(args)...);
0392 }
0393
0394
0395 template <typename... Args>
0396 result_of_t<T(Args...)> operator()(Args&&... args) const&
0397 {
0398 return this->target_(static_cast<Args&&>(args)...);
0399 }
0400
0401 private:
0402 typedef detail::executor_binder_base<T, Executor,
0403 uses_executor<T, Executor>::value> base_type;
0404 };
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414 template <typename Executor>
0415 struct partial_executor_binder
0416 {
0417
0418 explicit partial_executor_binder(const Executor& ex)
0419 : executor_(ex)
0420 {
0421 }
0422
0423
0424
0425 template <typename CompletionToken>
0426 BOOST_ASIO_NODISCARD inline
0427 constexpr executor_binder<decay_t<CompletionToken>, Executor>
0428 operator()(CompletionToken&& completion_token) const
0429 {
0430 return executor_binder<decay_t<CompletionToken>, Executor>(executor_arg_t(),
0431 static_cast<CompletionToken&&>(completion_token), executor_);
0432 }
0433
0434
0435 Executor executor_;
0436 };
0437
0438
0439 template <typename Executor>
0440 BOOST_ASIO_NODISCARD inline partial_executor_binder<Executor>
0441 bind_executor(const Executor& ex,
0442 constraint_t<
0443 is_executor<Executor>::value || execution::is_executor<Executor>::value
0444 > = 0)
0445 {
0446 return partial_executor_binder<Executor>(ex);
0447 }
0448
0449
0450 template <typename Executor, typename T>
0451 BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>, Executor>
0452 bind_executor(const Executor& ex, T&& t,
0453 constraint_t<
0454 is_executor<Executor>::value || execution::is_executor<Executor>::value
0455 > = 0)
0456 {
0457 return executor_binder<decay_t<T>, Executor>(
0458 executor_arg_t(), ex, static_cast<T&&>(t));
0459 }
0460
0461
0462
0463 template <typename ExecutionContext>
0464 BOOST_ASIO_NODISCARD inline partial_executor_binder<
0465 typename ExecutionContext::executor_type>
0466 bind_executor(ExecutionContext& ctx,
0467 constraint_t<
0468 is_convertible<ExecutionContext&, execution_context&>::value
0469 > = 0)
0470 {
0471 return partial_executor_binder<typename ExecutionContext::executor_type>(
0472 ctx.get_executor());
0473 }
0474
0475
0476 template <typename ExecutionContext, typename T>
0477 BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>,
0478 typename ExecutionContext::executor_type>
0479 bind_executor(ExecutionContext& ctx, T&& t,
0480 constraint_t<
0481 is_convertible<ExecutionContext&, execution_context&>::value
0482 > = 0)
0483 {
0484 return executor_binder<decay_t<T>, typename ExecutionContext::executor_type>(
0485 executor_arg_t(), ctx.get_executor(), static_cast<T&&>(t));
0486 }
0487
0488 #if !defined(GENERATING_DOCUMENTATION)
0489
0490 template <typename T, typename Executor>
0491 struct uses_executor<executor_binder<T, Executor>, Executor>
0492 : true_type {};
0493
0494 namespace detail {
0495
0496 template <typename TargetAsyncResult, typename Executor, typename = void>
0497 class executor_binder_completion_handler_async_result
0498 {
0499 public:
0500 template <typename T>
0501 explicit executor_binder_completion_handler_async_result(T&)
0502 {
0503 }
0504 };
0505
0506 template <typename TargetAsyncResult, typename Executor>
0507 class executor_binder_completion_handler_async_result<
0508 TargetAsyncResult, Executor,
0509 void_t<typename TargetAsyncResult::completion_handler_type >>
0510 {
0511 private:
0512 TargetAsyncResult target_;
0513
0514 public:
0515 typedef executor_binder<
0516 typename TargetAsyncResult::completion_handler_type, Executor>
0517 completion_handler_type;
0518
0519 explicit executor_binder_completion_handler_async_result(
0520 typename TargetAsyncResult::completion_handler_type& handler)
0521 : target_(handler)
0522 {
0523 }
0524
0525 auto get() -> decltype(target_.get())
0526 {
0527 return target_.get();
0528 }
0529 };
0530
0531 template <typename TargetAsyncResult, typename = void>
0532 struct executor_binder_async_result_return_type
0533 {
0534 };
0535
0536 template <typename TargetAsyncResult>
0537 struct executor_binder_async_result_return_type<TargetAsyncResult,
0538 void_t<typename TargetAsyncResult::return_type>>
0539 {
0540 typedef typename TargetAsyncResult::return_type return_type;
0541 };
0542
0543 }
0544
0545 template <typename T, typename Executor, typename Signature>
0546 class async_result<executor_binder<T, Executor>, Signature> :
0547 public detail::executor_binder_completion_handler_async_result<
0548 async_result<T, Signature>, Executor>,
0549 public detail::executor_binder_async_result_return_type<
0550 async_result<T, Signature>>
0551 {
0552 public:
0553 explicit async_result(executor_binder<T, Executor>& b)
0554 : detail::executor_binder_completion_handler_async_result<
0555 async_result<T, Signature>, Executor>(b.get())
0556 {
0557 }
0558
0559 template <typename Initiation>
0560 struct init_wrapper : detail::initiation_base<Initiation>
0561 {
0562 using detail::initiation_base<Initiation>::initiation_base;
0563
0564 template <typename Handler, typename... Args>
0565 void operator()(Handler&& handler, const Executor& e, Args&&... args) &&
0566 {
0567 static_cast<Initiation&&>(*this)(
0568 executor_binder<decay_t<Handler>, Executor>(
0569 executor_arg_t(), e, static_cast<Handler&&>(handler)),
0570 static_cast<Args&&>(args)...);
0571 }
0572
0573 template <typename Handler, typename... Args>
0574 void operator()(Handler&& handler,
0575 const Executor& e, Args&&... args) const &
0576 {
0577 static_cast<const Initiation&>(*this)(
0578 executor_binder<decay_t<Handler>, Executor>(
0579 executor_arg_t(), e, static_cast<Handler&&>(handler)),
0580 static_cast<Args&&>(args)...);
0581 }
0582 };
0583
0584 template <typename Initiation, typename RawCompletionToken, typename... Args>
0585 static auto initiate(Initiation&& initiation,
0586 RawCompletionToken&& token, Args&&... args)
0587 -> decltype(
0588 async_initiate<
0589 conditional_t<
0590 is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
0591 Signature>(
0592 declval<init_wrapper<decay_t<Initiation>>>(),
0593 token.get(), token.get_executor(), static_cast<Args&&>(args)...))
0594 {
0595 return async_initiate<
0596 conditional_t<
0597 is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
0598 Signature>(
0599 init_wrapper<decay_t<Initiation>>(
0600 static_cast<Initiation&&>(initiation)),
0601 token.get(), token.get_executor(), static_cast<Args&&>(args)...);
0602 }
0603
0604 private:
0605 async_result(const async_result&) = delete;
0606 async_result& operator=(const async_result&) = delete;
0607 };
0608
0609 template <typename Executor, typename... Signatures>
0610 struct async_result<partial_executor_binder<Executor>, Signatures...>
0611 {
0612 template <typename Initiation, typename RawCompletionToken, typename... Args>
0613 static auto initiate(Initiation&& initiation,
0614 RawCompletionToken&& token, Args&&... args)
0615 -> decltype(
0616 async_initiate<Signatures...>(
0617 static_cast<Initiation&&>(initiation),
0618 executor_binder<
0619 default_completion_token_t<associated_executor_t<Initiation>>,
0620 Executor>(executor_arg_t(), token.executor_,
0621 default_completion_token_t<associated_executor_t<Initiation>>{}),
0622 static_cast<Args&&>(args)...))
0623 {
0624 return async_initiate<Signatures...>(
0625 static_cast<Initiation&&>(initiation),
0626 executor_binder<
0627 default_completion_token_t<associated_executor_t<Initiation>>,
0628 Executor>(executor_arg_t(), token.executor_,
0629 default_completion_token_t<associated_executor_t<Initiation>>{}),
0630 static_cast<Args&&>(args)...);
0631 }
0632 };
0633
0634 template <template <typename, typename> class Associator,
0635 typename T, typename Executor, typename DefaultCandidate>
0636 struct associator<Associator, executor_binder<T, Executor>, DefaultCandidate>
0637 : Associator<T, DefaultCandidate>
0638 {
0639 static typename Associator<T, DefaultCandidate>::type get(
0640 const executor_binder<T, Executor>& b) noexcept
0641 {
0642 return Associator<T, DefaultCandidate>::get(b.get());
0643 }
0644
0645 static auto get(const executor_binder<T, Executor>& b,
0646 const DefaultCandidate& c) noexcept
0647 -> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
0648 {
0649 return Associator<T, DefaultCandidate>::get(b.get(), c);
0650 }
0651 };
0652
0653 template <typename T, typename Executor, typename Executor1>
0654 struct associated_executor<executor_binder<T, Executor>, Executor1>
0655 {
0656 typedef Executor type;
0657
0658 static auto get(const executor_binder<T, Executor>& b,
0659 const Executor1& = Executor1()) noexcept
0660 -> decltype(b.get_executor())
0661 {
0662 return b.get_executor();
0663 }
0664 };
0665
0666 #endif
0667
0668 }
0669 }
0670
0671 #include <boost/asio/detail/pop_options.hpp>
0672
0673 #endif