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