Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-15 09:44:13

0001 //
0002 // bind_executor.hpp
0003 // ~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
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 // defined(_MSC_VER) && (_MSC_VER >= 1200)
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 // Helper to automatically define nested typedef result_type.
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 // Helper to automatically define nested typedef argument_type.
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 // Helper to automatically define nested typedefs first_argument_type and
0124 // second_argument_type.
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 // Helper to perform uses_executor construction of the target type, if
0152 // required.
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 } // namespace detail
0188 
0189 /// A call wrapper type to bind an executor of type @c Executor to an object of
0190 /// type @c T.
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 // !defined(GENERATING_DOCUMENTATION)
0200 {
0201 public:
0202   /// The type of the target object.
0203   typedef T target_type;
0204 
0205   /// The type of the associated executor.
0206   typedef Executor executor_type;
0207 
0208 #if defined(GENERATING_DOCUMENTATION)
0209   /// The return type if a function.
0210   /**
0211    * The type of @c result_type is based on the type @c T of the wrapper's
0212    * target object:
0213    *
0214    * @li if @c T is a pointer to function type, @c result_type is a synonym for
0215    * the return type of @c T;
0216    *
0217    * @li if @c T is a class type with a member type @c result_type, then @c
0218    * result_type is a synonym for @c T::result_type;
0219    *
0220    * @li otherwise @c result_type is not defined.
0221    */
0222   typedef see_below result_type;
0223 
0224   /// The type of the function's argument.
0225   /**
0226    * The type of @c argument_type is based on the type @c T of the wrapper's
0227    * target object:
0228    *
0229    * @li if @c T is a pointer to a function type accepting a single argument,
0230    * @c argument_type is a synonym for the return type of @c T;
0231    *
0232    * @li if @c T is a class type with a member type @c argument_type, then @c
0233    * argument_type is a synonym for @c T::argument_type;
0234    *
0235    * @li otherwise @c argument_type is not defined.
0236    */
0237   typedef see_below argument_type;
0238 
0239   /// The type of the function's first argument.
0240   /**
0241    * The type of @c first_argument_type is based on the type @c T of the
0242    * wrapper's target object:
0243    *
0244    * @li if @c T is a pointer to a function type accepting two arguments, @c
0245    * first_argument_type is a synonym for the return type of @c T;
0246    *
0247    * @li if @c T is a class type with a member type @c first_argument_type,
0248    * then @c first_argument_type is a synonym for @c T::first_argument_type;
0249    *
0250    * @li otherwise @c first_argument_type is not defined.
0251    */
0252   typedef see_below first_argument_type;
0253 
0254   /// The type of the function's second argument.
0255   /**
0256    * The type of @c second_argument_type is based on the type @c T of the
0257    * wrapper's target object:
0258    *
0259    * @li if @c T is a pointer to a function type accepting two arguments, @c
0260    * second_argument_type is a synonym for the return type of @c T;
0261    *
0262    * @li if @c T is a class type with a member type @c first_argument_type,
0263    * then @c second_argument_type is a synonym for @c T::second_argument_type;
0264    *
0265    * @li otherwise @c second_argument_type is not defined.
0266    */
0267   typedef see_below second_argument_type;
0268 #endif // defined(GENERATING_DOCUMENTATION)
0269 
0270   /// Construct an executor wrapper for the specified object.
0271   /**
0272    * This constructor is only valid if the type @c T is constructible from type
0273    * @c U.
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   /// Copy constructor.
0283   executor_binder(const executor_binder& other)
0284     : base_type(other.get_executor(), other.get())
0285   {
0286   }
0287 
0288   /// Construct a copy, but specify a different executor.
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   /// Construct a copy of a different executor wrapper type.
0296   /**
0297    * This constructor is only valid if the @c Executor type is constructible
0298    * from type @c OtherExecutor, and the type @c T is constructible from type
0299    * @c U.
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   /// Construct a copy of a different executor wrapper type, but specify a
0310   /// different executor.
0311   /**
0312    * This constructor is only valid if the type @c T is constructible from type
0313    * @c U.
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   /// Move constructor.
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   /// Move construct the target object, but specify a different executor.
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   /// Move construct from a different executor wrapper type.
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   /// Move construct from a different executor wrapper type, but specify a
0348   /// different executor.
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   /// Destructor.
0358   ~executor_binder()
0359   {
0360   }
0361 
0362   /// Obtain a reference to the target object.
0363   target_type& get() noexcept
0364   {
0365     return this->target_;
0366   }
0367 
0368   /// Obtain a reference to the target object.
0369   const target_type& get() const noexcept
0370   {
0371     return this->target_;
0372   }
0373 
0374   /// Obtain the associated executor.
0375   executor_type get_executor() const noexcept
0376   {
0377     return this->executor_;
0378   }
0379 
0380   /// Forwarding function call operator.
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   /// Forwarding function call operator.
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   /// Forwarding function call operator.
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 /// A function object type that adapts a @ref completion_token to specify that
0407 /// the completion handler should have the supplied executor as its associated
0408 /// executor.
0409 /**
0410  * May also be used directly as a completion token, in which case it adapts the
0411  * asynchronous operation's default completion token (or boost::asio::deferred
0412  * if no default is available).
0413  */
0414 template <typename Executor>
0415 struct partial_executor_binder
0416 {
0417   /// Constructor that specifies associated executor.
0418   explicit partial_executor_binder(const Executor& ex)
0419     : executor_(ex)
0420   {
0421   }
0422 
0423   /// Adapt a @ref completion_token to specify that the completion handler
0424   /// should have the executor as its associated executor.
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 //private:
0435   Executor executor_;
0436 };
0437 
0438 /// Create a partial completion token that associates an executor.
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 /// Associate an object of type @c T with an executor of type @c Executor.
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 /// Create a partial completion token that associates an execution context's
0462 /// executor.
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 /// Associate an object of type @c T with an execution context's executor.
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 } // namespace detail
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 // !defined(GENERATING_DOCUMENTATION)
0667 
0668 } // namespace asio
0669 } // namespace boost
0670 
0671 #include <boost/asio/detail/pop_options.hpp>
0672 
0673 #endif // BOOST_ASIO_BIND_EXECUTOR_HPP