1 //
2 // io_object_executor.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 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_DETAIL_IO_OBJECT_EXECUTOR_HPP
12 #define BOOST_ASIO_DETAIL_IO_OBJECT_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/handler_invoke_helpers.hpp>
20 #include <boost/asio/detail/type_traits.hpp>
21 #include <boost/asio/io_context.hpp>
22 
23 #include <boost/asio/detail/push_options.hpp>
24 
25 namespace boost {
26 namespace asio {
27 namespace detail {
28 
29 // Wrap the (potentially polymorphic) executor so that we can bypass it when
30 // dispatching on a target executor that has a native I/O implementation.
31 template <typename Executor>
32 class io_object_executor
33 {
34 public:
io_object_executor(const Executor & ex,bool native_implementation)35   io_object_executor(const Executor& ex,
36       bool native_implementation) BOOST_ASIO_NOEXCEPT
37     : executor_(ex),
38       has_native_impl_(native_implementation)
39   {
40   }
41 
io_object_executor(const io_object_executor & other)42   io_object_executor(const io_object_executor& other) BOOST_ASIO_NOEXCEPT
43     : executor_(other.executor_),
44       has_native_impl_(other.has_native_impl_)
45   {
46   }
47 
48   template <typename Executor1>
io_object_executor(const io_object_executor<Executor1> & other)49   io_object_executor(
50       const io_object_executor<Executor1>& other) BOOST_ASIO_NOEXCEPT
51     : executor_(other.inner_executor()),
52       has_native_impl_(other.has_native_implementation())
53   {
54   }
55 
56 #if defined(BOOST_ASIO_HAS_MOVE)
io_object_executor(io_object_executor && other)57   io_object_executor(io_object_executor&& other) BOOST_ASIO_NOEXCEPT
58     : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)),
59       has_native_impl_(other.has_native_impl_)
60   {
61   }
62 #endif // defined(BOOST_ASIO_HAS_MOVE)
63 
inner_executor() const64   const Executor& inner_executor() const BOOST_ASIO_NOEXCEPT
65   {
66     return executor_;
67   }
68 
has_native_implementation() const69   bool has_native_implementation() const BOOST_ASIO_NOEXCEPT
70   {
71     return has_native_impl_;
72   }
73 
context() const74   execution_context& context() const BOOST_ASIO_NOEXCEPT
75   {
76     return executor_.context();
77   }
78 
on_work_started() const79   void on_work_started() const BOOST_ASIO_NOEXCEPT
80   {
81     if (is_same<Executor, io_context::executor_type>::value
82         || has_native_impl_)
83     {
84       // When using a native implementation, work is already counted by the
85       // execution context.
86     }
87     else
88     {
89       executor_.on_work_started();
90     }
91   }
92 
on_work_finished() const93   void on_work_finished() const BOOST_ASIO_NOEXCEPT
94   {
95     if (is_same<Executor, io_context::executor_type>::value
96         || has_native_impl_)
97     {
98       // When using a native implementation, work is already counted by the
99       // execution context.
100     }
101     else
102     {
103       executor_.on_work_finished();
104     }
105   }
106 
107   template <typename F, typename A>
dispatch(BOOST_ASIO_MOVE_ARG (F)f,const A & a) const108   void dispatch(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const
109   {
110     if (is_same<Executor, io_context::executor_type>::value
111         || has_native_impl_)
112     {
113       // When using a native implementation, I/O completion handlers are
114       // already dispatched according to the execution context's executor's
115       // rules. We can call the function directly.
116 #if defined(BOOST_ASIO_HAS_MOVE)
117       if (is_same<F, typename decay<F>::type>::value)
118       {
119         boost_asio_handler_invoke_helpers::invoke(f, f);
120         return;
121       }
122 #endif // defined(BOOST_ASIO_HAS_MOVE)
123       typename decay<F>::type function(BOOST_ASIO_MOVE_CAST(F)(f));
124       boost_asio_handler_invoke_helpers::invoke(function, function);
125     }
126     else
127     {
128       executor_.dispatch(BOOST_ASIO_MOVE_CAST(F)(f), a);
129     }
130   }
131 
132   template <typename F, typename A>
post(BOOST_ASIO_MOVE_ARG (F)f,const A & a) const133   void post(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const
134   {
135     executor_.post(BOOST_ASIO_MOVE_CAST(F)(f), a);
136   }
137 
138   template <typename F, typename A>
defer(BOOST_ASIO_MOVE_ARG (F)f,const A & a) const139   void defer(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const
140   {
141     executor_.defer(BOOST_ASIO_MOVE_CAST(F)(f), a);
142   }
143 
operator ==(const io_object_executor & a,const io_object_executor & b)144   friend bool operator==(const io_object_executor& a,
145       const io_object_executor& b) BOOST_ASIO_NOEXCEPT
146   {
147     return a.executor_ == b.executor_
148       && a.has_native_impl_ == b.has_native_impl_;
149   }
150 
operator !=(const io_object_executor & a,const io_object_executor & b)151   friend bool operator!=(const io_object_executor& a,
152       const io_object_executor& b) BOOST_ASIO_NOEXCEPT
153   {
154     return a.executor_ != b.executor_
155       || a.has_native_impl_ != b.has_native_impl_;
156   }
157 
158 private:
159   Executor executor_;
160   const bool has_native_impl_;
161 };
162 
163 } // namespace detail
164 } // namespace asio
165 } // namespace boost
166 
167 #include <boost/asio/detail/pop_options.hpp>
168 
169 #endif // BOOST_ASIO_DETAIL_IO_OBJECT_EXECUTOR_HPP
170