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