• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // detail/executor_function.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_DETAIL_EXECUTOR_FUNCTION_HPP
12 #define BOOST_ASIO_DETAIL_EXECUTOR_FUNCTION_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_alloc_helpers.hpp>
20 #include <boost/asio/detail/memory.hpp>
21 
22 #include <boost/asio/detail/push_options.hpp>
23 
24 namespace boost {
25 namespace asio {
26 namespace detail {
27 
28 #if defined(BOOST_ASIO_HAS_MOVE)
29 
30 // Lightweight, move-only function object wrapper.
31 class executor_function
32 {
33 public:
34   template <typename F, typename Alloc>
executor_function(F f,const Alloc & a)35   explicit executor_function(F f, const Alloc& a)
36   {
37     // Allocate and construct an object to wrap the function.
38     typedef impl<F, Alloc> impl_type;
39     typename impl_type::ptr p = {
40       detail::addressof(a), impl_type::ptr::allocate(a), 0 };
41     impl_ = new (p.v) impl_type(BOOST_ASIO_MOVE_CAST(F)(f), a);
42     p.v = 0;
43   }
44 
executor_function(executor_function && other)45   executor_function(executor_function&& other) BOOST_ASIO_NOEXCEPT
46     : impl_(other.impl_)
47   {
48     other.impl_ = 0;
49   }
50 
~executor_function()51   ~executor_function()
52   {
53     if (impl_)
54       impl_->complete_(impl_, false);
55   }
56 
operator ()()57   void operator()()
58   {
59     if (impl_)
60     {
61       impl_base* i = impl_;
62       impl_ = 0;
63       i->complete_(i, true);
64     }
65   }
66 
67 private:
68   // Base class for polymorphic function implementations.
69   struct impl_base
70   {
71     void (*complete_)(impl_base*, bool);
72   };
73 
74   // Polymorphic function implementation.
75   template <typename Function, typename Alloc>
76   struct impl : impl_base
77   {
78     BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(
79         thread_info_base::executor_function_tag, impl);
80 
81     template <typename F>
implboost::asio::detail::executor_function::impl82     impl(BOOST_ASIO_MOVE_ARG(F) f, const Alloc& a)
83       : function_(BOOST_ASIO_MOVE_CAST(F)(f)),
84         allocator_(a)
85     {
86       complete_ = &executor_function::complete<Function, Alloc>;
87     }
88 
89     Function function_;
90     Alloc allocator_;
91   };
92 
93   // Helper to complete function invocation.
94   template <typename Function, typename Alloc>
complete(impl_base * base,bool call)95   static void complete(impl_base* base, bool call)
96   {
97     // Take ownership of the function object.
98     impl<Function, Alloc>* i(static_cast<impl<Function, Alloc>*>(base));
99     Alloc allocator(i->allocator_);
100     typename impl<Function, Alloc>::ptr p = {
101       detail::addressof(allocator), i, i };
102 
103     // Make a copy of the function so that the memory can be deallocated before
104     // the upcall is made. Even if we're not about to make an upcall, a
105     // sub-object of the function may be the true owner of the memory
106     // associated with the function. Consequently, a local copy of the function
107     // is required to ensure that any owning sub-object remains valid until
108     // after we have deallocated the memory here.
109     Function function(BOOST_ASIO_MOVE_CAST(Function)(i->function_));
110     p.reset();
111 
112     // Make the upcall if required.
113     if (call)
114     {
115       function();
116     }
117   }
118 
119   impl_base* impl_;
120 };
121 
122 #else // defined(BOOST_ASIO_HAS_MOVE)
123 
124 // Not so lightweight, copyable function object wrapper.
125 class executor_function
126 {
127 public:
128   template <typename F, typename Alloc>
129   explicit executor_function(const F& f, const Alloc&)
130     : impl_(new impl<typename decay<F>::type>(f))
131   {
132   }
133 
134   void operator()()
135   {
136     impl_->complete_(impl_.get());
137   }
138 
139 private:
140   // Base class for polymorphic function implementations.
141   struct impl_base
142   {
143     void (*complete_)(impl_base*);
144   };
145 
146   // Polymorphic function implementation.
147   template <typename F>
148   struct impl : impl_base
149   {
150     impl(const F& f)
151       : function_(f)
152     {
153       complete_ = &executor_function::complete<F>;
154     }
155 
156     F function_;
157   };
158 
159   // Helper to complete function invocation.
160   template <typename F>
161   static void complete(impl_base* i)
162   {
163     static_cast<impl<F>*>(i)->function_();
164   }
165 
166   shared_ptr<impl_base> impl_;
167 };
168 
169 #endif // defined(BOOST_ASIO_HAS_MOVE)
170 
171 // Lightweight, non-owning, copyable function object wrapper.
172 class executor_function_view
173 {
174 public:
175   template <typename F>
executor_function_view(F & f)176   explicit executor_function_view(F& f) BOOST_ASIO_NOEXCEPT
177     : complete_(&executor_function_view::complete<F>),
178       function_(&f)
179   {
180   }
181 
operator ()()182   void operator()()
183   {
184     complete_(function_);
185   }
186 
187 private:
188   // Helper to complete function invocation.
189   template <typename F>
complete(void * f)190   static void complete(void* f)
191   {
192     (*static_cast<F*>(f))();
193   }
194 
195   void (*complete_)(void*);
196   void* function_;
197 };
198 
199 } // namespace detail
200 } // namespace asio
201 } // namespace boost
202 
203 #include <boost/asio/detail/pop_options.hpp>
204 
205 #endif // BOOST_ASIO_DETAIL_EXECUTOR_FUNCTION_HPP
206