]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | // |
92f5a8d4 | 2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) |
b32b8144 FG |
3 | // |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // Official repository: https://github.com/boostorg/beast | |
8 | // | |
9 | ||
10 | #ifndef BOOST_BEAST_DETAIL_BIND_HANDLER_HPP | |
11 | #define BOOST_BEAST_DETAIL_BIND_HANDLER_HPP | |
12 | ||
92f5a8d4 TL |
13 | #include <boost/beast/core/error.hpp> |
14 | #include <boost/beast/core/detail/tuple.hpp> | |
b32b8144 FG |
15 | #include <boost/asio/associated_allocator.hpp> |
16 | #include <boost/asio/associated_executor.hpp> | |
92f5a8d4 | 17 | #include <boost/asio/handler_alloc_hook.hpp> |
b32b8144 | 18 | #include <boost/asio/handler_continuation_hook.hpp> |
11fdf7f2 | 19 | #include <boost/asio/handler_invoke_hook.hpp> |
b32b8144 | 20 | #include <boost/core/ignore_unused.hpp> |
92f5a8d4 | 21 | #include <boost/mp11/integer_sequence.hpp> |
11fdf7f2 | 22 | #include <boost/is_placeholder.hpp> |
b32b8144 | 23 | #include <functional> |
92f5a8d4 | 24 | #include <type_traits> |
b32b8144 FG |
25 | #include <utility> |
26 | ||
27 | namespace boost { | |
28 | namespace beast { | |
29 | namespace detail { | |
30 | ||
92f5a8d4 TL |
31 | //------------------------------------------------------------------------------ |
32 | // | |
33 | // bind_handler | |
34 | // | |
35 | //------------------------------------------------------------------------------ | |
b32b8144 | 36 | |
b32b8144 | 37 | template<class Handler, class... Args> |
92f5a8d4 | 38 | class bind_wrapper |
b32b8144 | 39 | { |
92f5a8d4 | 40 | using args_type = detail::tuple<Args...>; |
b32b8144 FG |
41 | |
42 | Handler h_; | |
43 | args_type args_; | |
44 | ||
92f5a8d4 TL |
45 | template<class T, class Executor> |
46 | friend struct net::associated_executor; | |
47 | ||
48 | template<class T, class Allocator> | |
49 | friend struct net::associated_allocator; | |
50 | ||
b32b8144 FG |
51 | template<class Arg, class Vals> |
52 | static | |
53 | typename std::enable_if< | |
54 | std::is_placeholder<typename | |
11fdf7f2 TL |
55 | std::decay<Arg>::type>::value == 0 && |
56 | boost::is_placeholder<typename | |
b32b8144 | 57 | std::decay<Arg>::type>::value == 0, |
11fdf7f2 | 58 | Arg&&>::type |
92f5a8d4 | 59 | extract(Arg&& arg, Vals&& vals) |
b32b8144 FG |
60 | { |
61 | boost::ignore_unused(vals); | |
92f5a8d4 | 62 | return std::forward<Arg>(arg); |
b32b8144 FG |
63 | } |
64 | ||
65 | template<class Arg, class Vals> | |
66 | static | |
67 | typename std::enable_if< | |
68 | std::is_placeholder<typename | |
69 | std::decay<Arg>::type>::value != 0, | |
92f5a8d4 TL |
70 | tuple_element<std::is_placeholder< |
71 | typename std::decay<Arg>::type>::value - 1, | |
72 | Vals>>::type&& | |
b32b8144 FG |
73 | extract(Arg&&, Vals&& vals) |
74 | { | |
92f5a8d4 | 75 | return detail::get<std::is_placeholder< |
b32b8144 FG |
76 | typename std::decay<Arg>::type>::value - 1>( |
77 | std::forward<Vals>(vals)); | |
78 | } | |
79 | ||
11fdf7f2 TL |
80 | template<class Arg, class Vals> |
81 | static | |
82 | typename std::enable_if< | |
83 | boost::is_placeholder<typename | |
84 | std::decay<Arg>::type>::value != 0, | |
92f5a8d4 TL |
85 | tuple_element<boost::is_placeholder< |
86 | typename std::decay<Arg>::type>::value - 1, | |
87 | Vals>>::type&& | |
11fdf7f2 TL |
88 | extract(Arg&&, Vals&& vals) |
89 | { | |
92f5a8d4 | 90 | return detail::get<boost::is_placeholder< |
11fdf7f2 TL |
91 | typename std::decay<Arg>::type>::value - 1>( |
92 | std::forward<Vals>(vals)); | |
93 | } | |
94 | ||
92f5a8d4 | 95 | template<class ArgsTuple, std::size_t... S> |
b32b8144 FG |
96 | static |
97 | void | |
98 | invoke( | |
99 | Handler& h, | |
100 | ArgsTuple& args, | |
92f5a8d4 TL |
101 | tuple<>&&, |
102 | mp11::index_sequence<S...>) | |
b32b8144 FG |
103 | { |
104 | boost::ignore_unused(args); | |
92f5a8d4 | 105 | h(detail::get<S>(std::move(args))...); |
b32b8144 FG |
106 | } |
107 | ||
108 | template< | |
109 | class ArgsTuple, | |
110 | class ValsTuple, | |
111 | std::size_t... S> | |
112 | static | |
113 | void | |
114 | invoke( | |
115 | Handler& h, | |
116 | ArgsTuple& args, | |
117 | ValsTuple&& vals, | |
92f5a8d4 | 118 | mp11::index_sequence<S...>) |
b32b8144 FG |
119 | { |
120 | boost::ignore_unused(args); | |
121 | boost::ignore_unused(vals); | |
92f5a8d4 | 122 | h(extract(detail::get<S>(std::move(args)), |
b32b8144 FG |
123 | std::forward<ValsTuple>(vals))...); |
124 | } | |
125 | ||
126 | public: | |
92f5a8d4 | 127 | using result_type = void; // asio needs this |
b32b8144 | 128 | |
92f5a8d4 TL |
129 | bind_wrapper(bind_wrapper&&) = default; |
130 | bind_wrapper(bind_wrapper const&) = default; | |
b32b8144 | 131 | |
92f5a8d4 TL |
132 | template< |
133 | class DeducedHandler, | |
134 | class... Args_> | |
b32b8144 | 135 | explicit |
92f5a8d4 TL |
136 | bind_wrapper( |
137 | DeducedHandler&& handler, | |
138 | Args_&&... args) | |
b32b8144 | 139 | : h_(std::forward<DeducedHandler>(handler)) |
92f5a8d4 TL |
140 | , args_(std::forward<Args_>(args)...) |
141 | { | |
142 | } | |
143 | ||
144 | template<class... Values> | |
145 | void | |
146 | operator()(Values&&... values) | |
b32b8144 | 147 | { |
92f5a8d4 TL |
148 | invoke(h_, args_, |
149 | tuple<Values&&...>( | |
150 | std::forward<Values>(values)...), | |
151 | mp11::index_sequence_for<Args...>()); | |
b32b8144 FG |
152 | } |
153 | ||
92f5a8d4 TL |
154 | // |
155 | ||
156 | template<class Function> | |
157 | friend | |
158 | void asio_handler_invoke( | |
159 | Function&& f, bind_wrapper* op) | |
b32b8144 | 160 | { |
92f5a8d4 TL |
161 | using net::asio_handler_invoke; |
162 | asio_handler_invoke(f, std::addressof(op->h_)); | |
b32b8144 FG |
163 | } |
164 | ||
165 | friend | |
92f5a8d4 TL |
166 | bool asio_handler_is_continuation( |
167 | bind_wrapper* op) | |
b32b8144 | 168 | { |
92f5a8d4 TL |
169 | using net::asio_handler_is_continuation; |
170 | return asio_handler_is_continuation( | |
171 | std::addressof(op->h_)); | |
b32b8144 FG |
172 | } |
173 | ||
11fdf7f2 | 174 | friend |
92f5a8d4 TL |
175 | void* asio_handler_allocate( |
176 | std::size_t size, bind_wrapper* op) | |
11fdf7f2 | 177 | { |
92f5a8d4 TL |
178 | using net::asio_handler_allocate; |
179 | return asio_handler_allocate( | |
180 | size, std::addressof(op->h_)); | |
11fdf7f2 TL |
181 | } |
182 | ||
92f5a8d4 TL |
183 | friend |
184 | void asio_handler_deallocate( | |
185 | void* p, std::size_t size, bind_wrapper* op) | |
186 | { | |
187 | using net::asio_handler_deallocate; | |
188 | asio_handler_deallocate( | |
189 | p, size, std::addressof(op->h_)); | |
190 | } | |
191 | }; | |
192 | ||
193 | template<class Handler, class... Args> | |
194 | class bind_back_wrapper; | |
195 | ||
196 | template<class Handler, class... Args> | |
197 | class bind_front_wrapper; | |
198 | ||
199 | //------------------------------------------------------------------------------ | |
200 | // | |
201 | // bind_front | |
202 | // | |
203 | //------------------------------------------------------------------------------ | |
204 | ||
205 | template<class Handler, class... Args> | |
206 | class bind_front_wrapper | |
207 | { | |
208 | Handler h_; | |
209 | detail::tuple<Args...> args_; | |
210 | ||
211 | template<class T, class Executor> | |
212 | friend struct net::associated_executor; | |
213 | ||
214 | template<class T, class Allocator> | |
215 | friend struct net::associated_allocator; | |
216 | ||
217 | template<std::size_t... I, class... Ts> | |
b32b8144 | 218 | void |
92f5a8d4 TL |
219 | invoke( |
220 | std::false_type, | |
221 | mp11::index_sequence<I...>, | |
222 | Ts&&... ts) | |
b32b8144 | 223 | { |
92f5a8d4 TL |
224 | h_( detail::get<I>(std::move(args_))..., |
225 | std::forward<Ts>(ts)...); | |
b32b8144 FG |
226 | } |
227 | ||
92f5a8d4 | 228 | template<std::size_t... I, class... Ts> |
b32b8144 | 229 | void |
92f5a8d4 TL |
230 | invoke( |
231 | std::true_type, | |
232 | mp11::index_sequence<I...>, | |
233 | Ts&&... ts) | |
b32b8144 | 234 | { |
92f5a8d4 TL |
235 | std::mem_fn(h_)( |
236 | detail::get<I>(std::move(args_))..., | |
237 | std::forward<Ts>(ts)...); | |
238 | } | |
239 | ||
240 | public: | |
241 | using result_type = void; // asio needs this | |
242 | ||
243 | bind_front_wrapper(bind_front_wrapper&&) = default; | |
244 | bind_front_wrapper(bind_front_wrapper const&) = default; | |
245 | ||
246 | template<class Handler_, class... Args_> | |
247 | bind_front_wrapper( | |
248 | Handler_&& handler, | |
249 | Args_&&... args) | |
250 | : h_(std::forward<Handler_>(handler)) | |
251 | , args_(std::forward<Args_>(args)...) | |
252 | { | |
253 | } | |
254 | ||
255 | template<class... Ts> | |
256 | void operator()(Ts&&... ts) | |
257 | { | |
258 | invoke( | |
259 | std::is_member_function_pointer<Handler>{}, | |
260 | mp11::index_sequence_for<Args...>{}, | |
261 | std::forward<Ts>(ts)...); | |
262 | } | |
263 | ||
264 | // | |
265 | ||
266 | template<class Function> | |
267 | friend | |
268 | void asio_handler_invoke( | |
269 | Function&& f, bind_front_wrapper* op) | |
270 | { | |
271 | using net::asio_handler_invoke; | |
272 | asio_handler_invoke(f, std::addressof(op->h_)); | |
273 | } | |
274 | ||
275 | friend | |
276 | bool asio_handler_is_continuation( | |
277 | bind_front_wrapper* op) | |
278 | { | |
279 | using net::asio_handler_is_continuation; | |
280 | return asio_handler_is_continuation( | |
281 | std::addressof(op->h_)); | |
282 | } | |
283 | ||
284 | friend | |
285 | void* asio_handler_allocate( | |
286 | std::size_t size, bind_front_wrapper* op) | |
287 | { | |
288 | using net::asio_handler_allocate; | |
289 | return asio_handler_allocate( | |
290 | size, std::addressof(op->h_)); | |
291 | } | |
292 | ||
293 | friend | |
294 | void asio_handler_deallocate( | |
295 | void* p, std::size_t size, bind_front_wrapper* op) | |
296 | { | |
297 | using net::asio_handler_deallocate; | |
298 | asio_handler_deallocate( | |
299 | p, size, std::addressof(op->h_)); | |
b32b8144 FG |
300 | } |
301 | }; | |
302 | ||
303 | } // detail | |
304 | } // beast | |
92f5a8d4 | 305 | } // boost |
b32b8144 | 306 | |
92f5a8d4 TL |
307 | //------------------------------------------------------------------------------ |
308 | ||
309 | namespace boost { | |
b32b8144 | 310 | namespace asio { |
92f5a8d4 | 311 | |
b32b8144 FG |
312 | template<class Handler, class... Args, class Executor> |
313 | struct associated_executor< | |
92f5a8d4 | 314 | beast::detail::bind_wrapper<Handler, Args...>, Executor> |
b32b8144 FG |
315 | { |
316 | using type = typename | |
317 | associated_executor<Handler, Executor>::type; | |
318 | ||
319 | static | |
320 | type | |
92f5a8d4 TL |
321 | get(beast::detail::bind_wrapper<Handler, Args...> const& op, |
322 | Executor const& ex = Executor{}) noexcept | |
b32b8144 FG |
323 | { |
324 | return associated_executor< | |
92f5a8d4 | 325 | Handler, Executor>::get(op.h_, ex); |
b32b8144 FG |
326 | } |
327 | }; | |
b32b8144 | 328 | |
92f5a8d4 TL |
329 | template<class Handler, class... Args, class Executor> |
330 | struct associated_executor< | |
331 | beast::detail::bind_front_wrapper<Handler, Args...>, Executor> | |
332 | { | |
333 | using type = typename | |
334 | associated_executor<Handler, Executor>::type; | |
335 | ||
336 | static | |
337 | type | |
338 | get(beast::detail::bind_front_wrapper<Handler, Args...> const& op, | |
339 | Executor const& ex = Executor{}) noexcept | |
340 | { | |
341 | return associated_executor< | |
342 | Handler, Executor>::get(op.h_, ex); | |
343 | } | |
344 | }; | |
345 | ||
346 | // | |
347 | ||
348 | template<class Handler, class... Args, class Allocator> | |
349 | struct associated_allocator< | |
350 | beast::detail::bind_wrapper<Handler, Args...>, Allocator> | |
351 | { | |
352 | using type = typename | |
353 | associated_allocator<Handler, Allocator>::type; | |
354 | ||
355 | static | |
356 | type | |
357 | get(beast::detail::bind_wrapper<Handler, Args...> const& op, | |
358 | Allocator const& alloc = Allocator{}) noexcept | |
359 | { | |
360 | return associated_allocator< | |
361 | Handler, Allocator>::get(op.h_, alloc); | |
362 | } | |
363 | }; | |
364 | ||
365 | template<class Handler, class... Args, class Allocator> | |
366 | struct associated_allocator< | |
367 | beast::detail::bind_front_wrapper<Handler, Args...>, Allocator> | |
368 | { | |
369 | using type = typename | |
370 | associated_allocator<Handler, Allocator>::type; | |
371 | ||
372 | static | |
373 | type | |
374 | get(beast::detail::bind_front_wrapper<Handler, Args...> const& op, | |
375 | Allocator const& alloc = Allocator{}) noexcept | |
376 | { | |
377 | return associated_allocator< | |
378 | Handler, Allocator>::get(op.h_, alloc); | |
379 | } | |
380 | }; | |
381 | ||
382 | } // asio | |
b32b8144 FG |
383 | } // boost |
384 | ||
92f5a8d4 TL |
385 | //------------------------------------------------------------------------------ |
386 | ||
b32b8144 | 387 | namespace std { |
92f5a8d4 TL |
388 | |
389 | // VFALCO Using std::bind on a completion handler will | |
390 | // cause undefined behavior later, because the executor | |
391 | // associated with the handler is not propagated to the | |
392 | // wrapper returned by std::bind; these overloads are | |
393 | // deleted to prevent mistakes. If this creates a problem | |
394 | // please contact me. | |
395 | ||
b32b8144 FG |
396 | template<class Handler, class... Args> |
397 | void | |
92f5a8d4 | 398 | bind(boost::beast::detail::bind_wrapper< |
b32b8144 | 399 | Handler, Args...>, ...) = delete; |
92f5a8d4 TL |
400 | |
401 | template<class Handler, class... Args> | |
402 | void | |
403 | bind(boost::beast::detail::bind_front_wrapper< | |
404 | Handler, Args...>, ...) = delete; | |
405 | ||
b32b8144 FG |
406 | } // std |
407 | ||
92f5a8d4 TL |
408 | //------------------------------------------------------------------------------ |
409 | ||
b32b8144 | 410 | #endif |