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