Clementine
handler_work.hpp
1 //
2 // detail/handler_work.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 ASIO_DETAIL_HANDLER_WORK_HPP
12 #define ASIO_DETAIL_HANDLER_WORK_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include "asio/detail/config.hpp"
19 #include "asio/associated_executor.hpp"
20 #include "asio/detail/handler_invoke_helpers.hpp"
21 #include "asio/detail/type_traits.hpp"
22 #include "asio/execution/allocator.hpp"
23 #include "asio/execution/blocking.hpp"
24 #include "asio/execution/execute.hpp"
25 #include "asio/execution/executor.hpp"
26 #include "asio/execution/outstanding_work.hpp"
27 #include "asio/executor_work_guard.hpp"
28 #include "asio/prefer.hpp"
29 
30 #include "asio/detail/push_options.hpp"
31 
32 namespace asio {
33 
34 class executor;
35 class io_context;
36 
37 namespace execution {
38 
39 #if defined(ASIO_HAS_VARIADIC_TEMPLATES)
40 
41 template <typename...> class any_executor;
42 
43 #else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
44 
45 template <typename, typename, typename, typename, typename,
46  typename, typename, typename, typename> class any_executor;
47 
48 #endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
49 
50 } // namespace execution
51 namespace detail {
52 
53 template <typename Executor, typename CandidateExecutor = void,
54  typename IoContext = io_context,
55  typename PolymorphicExecutor = executor, typename = void>
57 {
58 public:
59  explicit handler_work_base(const Executor& ex) ASIO_NOEXCEPT
60  : executor_(asio::prefer(ex, execution::outstanding_work.tracked))
61  {
62  }
63 
64  template <typename OtherExecutor>
65  handler_work_base(const Executor& ex,
66  const OtherExecutor&) ASIO_NOEXCEPT
67  : executor_(asio::prefer(ex, execution::outstanding_work.tracked))
68  {
69  }
70 
71  handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT
72  : executor_(other.executor_)
73  {
74  }
75 
76 #if defined(ASIO_HAS_MOVE)
77  handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT
78  : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_))
79  {
80  }
81 #endif // defined(ASIO_HAS_MOVE)
82 
83  bool owns_work() const ASIO_NOEXCEPT
84  {
85  return true;
86  }
87 
88  template <typename Function, typename Handler>
89  void dispatch(Function& function, Handler& handler)
90  {
91  execution::execute(
92  asio::prefer(executor_,
93  execution::blocking.possibly,
94  execution::allocator((get_associated_allocator)(handler))),
95  ASIO_MOVE_CAST(Function)(function));
96  }
97 
98 private:
99  typedef typename decay<
100  typename prefer_result<Executor,
102  >::type
103  >::type executor_type;
104 
105  executor_type executor_;
106 };
107 
108 template <typename Executor, typename CandidateExecutor,
109  typename IoContext, typename PolymorphicExecutor>
110 class handler_work_base<Executor, CandidateExecutor,
111  IoContext, PolymorphicExecutor,
112  typename enable_if<
113  !execution::is_executor<Executor>::value
114  && (!is_same<Executor, PolymorphicExecutor>::value
115  || !is_same<CandidateExecutor, void>::value)
116  >::type>
117 {
118 public:
119  explicit handler_work_base(const Executor& ex) ASIO_NOEXCEPT
120  : executor_(ex),
121  owns_work_(true)
122  {
123  executor_.on_work_started();
124  }
125 
126  handler_work_base(const Executor& ex,
127  const Executor& candidate) ASIO_NOEXCEPT
128  : executor_(ex),
129  owns_work_(ex != candidate)
130  {
131  if (owns_work_)
132  executor_.on_work_started();
133  }
134 
135  template <typename OtherExecutor>
136  handler_work_base(const Executor& ex,
137  const OtherExecutor&) ASIO_NOEXCEPT
138  : executor_(ex),
139  owns_work_(true)
140  {
141  executor_.on_work_started();
142  }
143 
144  handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT
145  : executor_(other.executor_),
146  owns_work_(other.owns_work_)
147  {
148  if (owns_work_)
149  executor_.on_work_started();
150  }
151 
152 #if defined(ASIO_HAS_MOVE)
153  handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT
154  : executor_(ASIO_MOVE_CAST(Executor)(other.executor_)),
155  owns_work_(other.owns_work_)
156  {
157  other.owns_work_ = false;
158  }
159 #endif // defined(ASIO_HAS_MOVE)
160 
162  {
163  if (owns_work_)
164  executor_.on_work_finished();
165  }
166 
167  bool owns_work() const ASIO_NOEXCEPT
168  {
169  return owns_work_;
170  }
171 
172  template <typename Function, typename Handler>
173  void dispatch(Function& function, Handler& handler)
174  {
175  executor_.dispatch(ASIO_MOVE_CAST(Function)(function),
176  asio::get_associated_allocator(handler));
177  }
178 
179 private:
180  Executor executor_;
181  bool owns_work_;
182 };
183 
184 template <typename Executor, typename IoContext, typename PolymorphicExecutor>
185 class handler_work_base<Executor, void, IoContext, PolymorphicExecutor,
186  typename enable_if<
187  is_same<
188  Executor,
189  typename IoContext::executor_type
190  >::value
191  >::type>
192 {
193 public:
194  explicit handler_work_base(const Executor&)
195  {
196  }
197 
198  bool owns_work() const ASIO_NOEXCEPT
199  {
200  return false;
201  }
202 
203  template <typename Function, typename Handler>
204  void dispatch(Function& function, Handler& handler)
205  {
206  // When using a native implementation, I/O completion handlers are
207  // already dispatched according to the execution context's executor's
208  // rules. We can call the function directly.
209  asio_handler_invoke_helpers::invoke(function, handler);
210  }
211 };
212 
213 template <typename Executor, typename IoContext>
214 class handler_work_base<Executor, void, IoContext, Executor>
215 {
216 public:
217  explicit handler_work_base(const Executor& ex) ASIO_NOEXCEPT
218 #if !defined(ASIO_NO_TYPEID)
219  : executor_(
220  ex.target_type() == typeid(typename IoContext::executor_type)
221  ? Executor() : ex)
222 #else // !defined(ASIO_NO_TYPEID)
223  : executor_(ex)
224 #endif // !defined(ASIO_NO_TYPEID)
225  {
226  if (executor_)
227  executor_.on_work_started();
228  }
229 
230  handler_work_base(const Executor& ex,
231  const Executor& candidate) ASIO_NOEXCEPT
232  : executor_(ex != candidate ? ex : Executor())
233  {
234  if (executor_)
235  executor_.on_work_started();
236  }
237 
238  template <typename OtherExecutor>
239  handler_work_base(const Executor& ex,
240  const OtherExecutor&) ASIO_NOEXCEPT
241  : executor_(ex)
242  {
243  executor_.on_work_started();
244  }
245 
246  handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT
247  : executor_(other.executor_)
248  {
249  if (executor_)
250  executor_.on_work_started();
251  }
252 
253 #if defined(ASIO_HAS_MOVE)
254  handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT
255  : executor_(ASIO_MOVE_CAST(Executor)(other.executor_))
256  {
257  }
258 #endif // defined(ASIO_HAS_MOVE)
259 
261  {
262  if (executor_)
263  executor_.on_work_finished();
264  }
265 
266  bool owns_work() const ASIO_NOEXCEPT
267  {
268  return !!executor_;
269  }
270 
271  template <typename Function, typename Handler>
272  void dispatch(Function& function, Handler& handler)
273  {
274  executor_.dispatch(ASIO_MOVE_CAST(Function)(function),
275  asio::get_associated_allocator(handler));
276  }
277 
278 private:
279  Executor executor_;
280 };
281 
282 template <
283 #if defined(ASIO_HAS_VARIADIC_TEMPLATES)
284  typename... SupportableProperties,
285 #else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
286  typename T1, typename T2, typename T3, typename T4, typename T5,
287  typename T6, typename T7, typename T8, typename T9,
288 #endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
289  typename IoContext, typename PolymorphicExecutor>
291 #if defined(ASIO_HAS_VARIADIC_TEMPLATES)
292  execution::any_executor<SupportableProperties...>,
293 #else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
294  execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>,
295 #endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
296  void, IoContext, PolymorphicExecutor>
297 {
298 public:
299  typedef
300 #if defined(ASIO_HAS_VARIADIC_TEMPLATES)
301  execution::any_executor<SupportableProperties...>
302 #else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
304 #endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
306 
307  explicit handler_work_base(const executor_type& ex) ASIO_NOEXCEPT
308 #if !defined(ASIO_NO_TYPEID)
309  : executor_(
310  ex.target_type() == typeid(typename IoContext::executor_type)
311  ? executor_type()
312  : asio::prefer(ex, execution::outstanding_work.tracked))
313 #else // !defined(ASIO_NO_TYPEID)
314  : executor_(asio::prefer(ex, execution::outstanding_work.tracked))
315 #endif // !defined(ASIO_NO_TYPEID)
316  {
317  }
318 
319  handler_work_base(const executor_type& ex,
320  const executor_type& candidate) ASIO_NOEXCEPT
321  : executor_(ex != candidate ? ex : executor_type())
322  {
323  }
324 
325  template <typename OtherExecutor>
326  handler_work_base(const executor_type& ex,
327  const OtherExecutor&) ASIO_NOEXCEPT
328  : executor_(asio::prefer(ex, execution::outstanding_work.tracked))
329  {
330  }
331 
332  handler_work_base(const handler_work_base& other) ASIO_NOEXCEPT
333  : executor_(other.executor_)
334  {
335  }
336 
337 #if defined(ASIO_HAS_MOVE)
338  handler_work_base(handler_work_base&& other) ASIO_NOEXCEPT
339  : executor_(ASIO_MOVE_CAST(executor_type)(other.executor_))
340  {
341  }
342 #endif // defined(ASIO_HAS_MOVE)
343 
344  bool owns_work() const ASIO_NOEXCEPT
345  {
346  return !!executor_;
347  }
348 
349  template <typename Function, typename Handler>
350  void dispatch(Function& function, Handler& handler)
351  {
352  execution::execute(
353  asio::prefer(executor_,
354  execution::blocking.possibly,
355  execution::allocator((get_associated_allocator)(handler))),
356  ASIO_MOVE_CAST(Function)(function));
357  }
358 
359 private:
360  executor_type executor_;
361 };
362 
363 template <typename Handler, typename IoExecutor, typename = void>
365  handler_work_base<IoExecutor>,
366  handler_work_base<typename associated_executor<
367  Handler, IoExecutor>::type, IoExecutor>
368 {
369 public:
371  typedef handler_work_base<typename associated_executor<
372  Handler, IoExecutor>::type, IoExecutor> base2_type;
373 
374  handler_work(Handler& handler, const IoExecutor& io_ex) ASIO_NOEXCEPT
375  : base1_type(io_ex),
376  base2_type(asio::get_associated_executor(handler, io_ex), io_ex)
377  {
378  }
379 
380  template <typename Function>
381  void complete(Function& function, Handler& handler)
382  {
383  if (!base1_type::owns_work() && !base2_type::owns_work())
384  {
385  // When using a native implementation, I/O completion handlers are
386  // already dispatched according to the execution context's executor's
387  // rules. We can call the function directly.
388  asio_handler_invoke_helpers::invoke(function, handler);
389  }
390  else
391  {
392  base2_type::dispatch(function, handler);
393  }
394  }
395 };
396 
397 template <typename Handler, typename IoExecutor>
399  Handler, IoExecutor,
400  typename enable_if<
401  is_same<
402  typename associated_executor<Handler,
403  IoExecutor>::asio_associated_executor_is_unspecialised,
404  void
405  >::value
406  >::type> : handler_work_base<IoExecutor>
407 {
408 public:
410 
411  handler_work(Handler&, const IoExecutor& io_ex) ASIO_NOEXCEPT
412  : base1_type(io_ex)
413  {
414  }
415 
416  template <typename Function>
417  void complete(Function& function, Handler& handler)
418  {
419  if (!base1_type::owns_work())
420  {
421  // When using a native implementation, I/O completion handlers are
422  // already dispatched according to the execution context's executor's
423  // rules. We can call the function directly.
424  asio_handler_invoke_helpers::invoke(function, handler);
425  }
426  else
427  {
428  base1_type::dispatch(function, handler);
429  }
430  }
431 };
432 
433 } // namespace detail
434 } // namespace asio
435 
436 #include "asio/detail/pop_options.hpp"
437 
438 #endif // ASIO_DETAIL_HANDLER_WORK_HPP
Definition: handler_work.hpp:364
Definition: bulk_execute.cpp:152
Polymorphic wrapper for executors.
Definition: executor.hpp:47
Provides core I/O functionality.
Definition: io_context.hpp:211
Definition: chrono.h:284
Definition: is_executor.hpp:114
Definition: type_traits.hpp:97
Definition: handler_work.hpp:46
Definition: outstanding_work.hpp:153
Traits type used to obtain the executor associated with an object.
Definition: associated_executor.hpp:76
Definition: prefer.hpp:623
Definition: handler_work.hpp:37
Definition: any_io_executor.hpp:28
Definition: handler_work.hpp:56