1 //
2 // impl/defer.hpp
3 // ~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2020 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_IMPL_DEFER_HPP
12 #define BOOST_ASIO_IMPL_DEFER_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/associated_allocator.hpp>
20 #include <boost/asio/associated_executor.hpp>
21 #include <boost/asio/detail/work_dispatcher.hpp>
22 #include <boost/asio/execution/allocator.hpp>
23 #include <boost/asio/execution/blocking.hpp>
24 #include <boost/asio/execution/relationship.hpp>
25 #include <boost/asio/prefer.hpp>
26 #include <boost/asio/require.hpp>
27 
28 #include <boost/asio/detail/push_options.hpp>
29 
30 namespace boost {
31 namespace asio {
32 namespace detail {
33 
34 class initiate_defer
35 {
36 public:
37   template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<execution::is_executor<typename associated_executor<typename decay<CompletionHandler>::type>::type>::value>::type * =0) const38   void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
39       typename enable_if<
40         execution::is_executor<
41           typename associated_executor<
42             typename decay<CompletionHandler>::type
43           >::type
44         >::value
45       >::type* = 0) const
46   {
47     typedef typename decay<CompletionHandler>::type handler_t;
48 
49     typename associated_executor<handler_t>::type ex(
50         (get_associated_executor)(handler));
51 
52     typename associated_allocator<handler_t>::type alloc(
53         (get_associated_allocator)(handler));
54 
55     execution::execute(
56         boost::asio::prefer(
57           boost::asio::require(ex, execution::blocking.never),
58           execution::relationship.continuation,
59           execution::allocator(alloc)),
60         BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler));
61   }
62 
63   template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<!execution::is_executor<typename associated_executor<typename decay<CompletionHandler>::type>::type>::value>::type * =0) const64   void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
65       typename enable_if<
66         !execution::is_executor<
67           typename associated_executor<
68             typename decay<CompletionHandler>::type
69           >::type
70         >::value
71       >::type* = 0) const
72   {
73     typedef typename decay<CompletionHandler>::type handler_t;
74 
75     typename associated_executor<handler_t>::type ex(
76         (get_associated_executor)(handler));
77 
78     typename associated_allocator<handler_t>::type alloc(
79         (get_associated_allocator)(handler));
80 
81     ex.defer(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);
82   }
83 };
84 
85 template <typename Executor>
86 class initiate_defer_with_executor
87 {
88 public:
89   typedef Executor executor_type;
90 
initiate_defer_with_executor(const Executor & ex)91   explicit initiate_defer_with_executor(const Executor& ex)
92     : ex_(ex)
93   {
94   }
95 
get_executor() const96   executor_type get_executor() const BOOST_ASIO_NOEXCEPT
97   {
98     return ex_;
99   }
100 
101   template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<execution::is_executor<typename conditional<true,executor_type,CompletionHandler>::type>::value &&!detail::is_work_dispatcher_required<typename decay<CompletionHandler>::type,Executor>::value>::type * =0) const102   void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
103       typename enable_if<
104         execution::is_executor<
105           typename conditional<true, executor_type, CompletionHandler>::type
106         >::value
107         &&
108         !detail::is_work_dispatcher_required<
109           typename decay<CompletionHandler>::type,
110           Executor
111         >::value
112       >::type* = 0) const
113   {
114     typedef typename decay<CompletionHandler>::type handler_t;
115 
116     typename associated_allocator<handler_t>::type alloc(
117         (get_associated_allocator)(handler));
118 
119     execution::execute(
120         boost::asio::prefer(
121           boost::asio::require(ex_, execution::blocking.never),
122           execution::relationship.continuation,
123           execution::allocator(alloc)),
124         BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler));
125   }
126 
127   template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<execution::is_executor<typename conditional<true,executor_type,CompletionHandler>::type>::value && detail::is_work_dispatcher_required<typename decay<CompletionHandler>::type,Executor>::value>::type * =0) const128   void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
129       typename enable_if<
130         execution::is_executor<
131           typename conditional<true, executor_type, CompletionHandler>::type
132         >::value
133         &&
134         detail::is_work_dispatcher_required<
135           typename decay<CompletionHandler>::type,
136           Executor
137         >::value
138       >::type* = 0) const
139   {
140     typedef typename decay<CompletionHandler>::type handler_t;
141 
142     typedef typename associated_executor<
143       handler_t, Executor>::type handler_ex_t;
144     handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
145 
146     typename associated_allocator<handler_t>::type alloc(
147         (get_associated_allocator)(handler));
148 
149     execution::execute(
150         boost::asio::prefer(
151           boost::asio::require(ex_, execution::blocking.never),
152           execution::relationship.continuation,
153           execution::allocator(alloc)),
154         detail::work_dispatcher<handler_t, handler_ex_t>(
155           BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex));
156   }
157 
158   template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<!execution::is_executor<typename conditional<true,executor_type,CompletionHandler>::type>::value &&!detail::is_work_dispatcher_required<typename decay<CompletionHandler>::type,Executor>::value>::type * =0) const159   void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
160       typename enable_if<
161         !execution::is_executor<
162           typename conditional<true, executor_type, CompletionHandler>::type
163         >::value
164         &&
165         !detail::is_work_dispatcher_required<
166           typename decay<CompletionHandler>::type,
167           Executor
168         >::value
169       >::type* = 0) const
170   {
171     typedef typename decay<CompletionHandler>::type handler_t;
172 
173     typename associated_allocator<handler_t>::type alloc(
174         (get_associated_allocator)(handler));
175 
176     ex_.defer(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc);
177   }
178 
179   template <typename CompletionHandler>
operator ()(BOOST_ASIO_MOVE_ARG (CompletionHandler)handler,typename enable_if<!execution::is_executor<typename conditional<true,executor_type,CompletionHandler>::type>::value && detail::is_work_dispatcher_required<typename decay<CompletionHandler>::type,Executor>::value>::type * =0) const180   void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler,
181       typename enable_if<
182         !execution::is_executor<
183           typename conditional<true, executor_type, CompletionHandler>::type
184         >::value
185         &&
186         detail::is_work_dispatcher_required<
187           typename decay<CompletionHandler>::type,
188           Executor
189         >::value
190       >::type* = 0) const
191   {
192     typedef typename decay<CompletionHandler>::type handler_t;
193 
194     typedef typename associated_executor<
195       handler_t, Executor>::type handler_ex_t;
196     handler_ex_t handler_ex((get_associated_executor)(handler, ex_));
197 
198     typename associated_allocator<handler_t>::type alloc(
199         (get_associated_allocator)(handler));
200 
201     ex_.defer(detail::work_dispatcher<handler_t, handler_ex_t>(
202           BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler),
203           handler_ex), alloc);
204   }
205 
206 private:
207   Executor ex_;
208 };
209 
210 } // namespace detail
211 
212 template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,void ())213 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
214     BOOST_ASIO_MOVE_ARG(CompletionToken) token)
215 {
216   return async_initiate<CompletionToken, void()>(
217       detail::initiate_defer(), token);
218 }
219 
220 template <typename Executor,
221     BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,void ())222 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
223     const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token,
224     typename enable_if<
225       execution::is_executor<Executor>::value || is_executor<Executor>::value
226     >::type*)
227 {
228   return async_initiate<CompletionToken, void()>(
229       detail::initiate_defer_with_executor<Executor>(ex), token);
230 }
231 
232 template <typename ExecutionContext,
233     BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,void ())234 inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer(
235     ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token,
236     typename enable_if<is_convertible<
237       ExecutionContext&, execution_context&>::value>::type*)
238 {
239   return async_initiate<CompletionToken, void()>(
240       detail::initiate_defer_with_executor<
241         typename ExecutionContext::executor_type>(
242           ctx.get_executor()), token);
243 }
244 
245 } // namespace asio
246 } // namespace boost
247 
248 #include <boost/asio/detail/pop_options.hpp>
249 
250 #endif // BOOST_ASIO_IMPL_DEFER_HPP
251