Turi Create  4.0
dispatch_impl.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef CPPIPC_SERVER_DISPATCH_IMPL_HPP
7 #define CPPIPC_SERVER_DISPATCH_IMPL_HPP
8 
9 #include <tuple>
10 #include <type_traits>
11 #include <boost/function.hpp>
12 #include <boost/type_traits.hpp>
13 #include <boost/function_types/function_type.hpp>
14 #include <boost/function_types/parameter_types.hpp>
15 #include <core/storage/serialization/iarchive.hpp>
16 #include <core/storage/serialization/oarchive.hpp>
17 #include <core/generics/remove_member_pointer.hpp>
18 #include <core/system/cppipc/ipc_object_base.hpp>
19 #include <core/system/cppipc/util/generics/member_function_return_type.hpp>
20 #include <core/system/cppipc/util/generics/tuple.hpp>
21 #include <core/system/cppipc/server/dispatch.hpp>
22 #include <core/system/cppipc/server/comm_server.hpp>
23 #include <core/system/cppipc/common/ipc_deserializer.hpp>
24 
25 namespace cppipc {
26 
27 namespace detail{
28 /**
29  * \internal
30  * \ingroup cppipc
31  * Internal utility function.
32  * Calls the function, and serializes the result.
33  * Works correctly for void types.
34  */
35 template <typename RetType, typename T, typename MemFn, typename... Args>
36 struct exec_and_serialize_response {
37  static void exec(T* objectptr,
38  comm_server* server,
39  MemFn fn,
40  turi::oarchive& response,
41  Args&... args) {
42  auto ret = (objectptr->*fn)(std::forward<Args>(args)...);
43  detail::set_deserializer_to_server(server);
44  response << ret;
45  }
46 };
47 
48 
49 /**
50  * \internal
51  * \ingroup cppipc
52  * Specialization of exec_and_serialize_response to handle void return types.
53  */
54 template <typename T, typename MemFn, typename... Args>
55 struct exec_and_serialize_response<void, T, MemFn, Args...> {
56  static void exec(T* objectptr,
57  comm_server* server,
58  MemFn fn,
59  turi::oarchive& response,
60  Args&... args) {
61  (objectptr->*fn)(std::forward<Args>(args)...);
62  }
63 };
64 
65 
66 /**:
67  * \internal
68  * \ingroup cppipc
69  * Recursively extracts one argument at a time from the left, and calling
70  * execute_disect again with one less element in the tuple. When the tuple is
71  * empty the second overload is called.
72  */
73 template <typename T, typename Memfn, typename ArgumentTuple, typename... Args>
75  static void exec(T* objectptr,
76  comm_server* server,
77  Memfn fn,
78  turi::iarchive& msg,
79  turi::oarchive& response,
80  Args&... args) {
81  typedef typename std::tuple_element<0, ArgumentTuple>::type arg_type;
82  typedef typename std::decay<arg_type>::type decayed_type;
83  decayed_type arg = decayed_type();
84  msg >> arg;
85  typedef typename left_shift_tuple<ArgumentTuple>::type shifted_tuple;
87  server,
88  fn,
89  msg,
90  response,
91  args...,
92  arg);
93  }
94 };
95 
96 
97 /**
98  * \internal
99  * \ingroup cppipc
100  * Overload of execute_disect when the tuple list is empty.
101  * Here we just forward the call to the function.
102  */
103 template <typename T, typename Memfn, typename... Args>
104 struct execute_disect<T, Memfn, std::tuple<>, Args...> {
105  static void exec(T* objectptr,
106  comm_server* server,
107  Memfn fn,
108  turi::iarchive& msg,
109  turi::oarchive& response,
110  Args&... args) {
111  typedef typename member_function_return_type<Memfn>::type return_type;
112  exec_and_serialize_response<return_type,
113  T,
114  Memfn,
115  Args...>::exec(objectptr, server, fn, response, args...);
116  }
117 };
118 
119 
120 
121 /**
122  * \internal
123  * \ingroup cppipc
124  * A wrapper around the execute_disect call structs.
125  * Achieves the effect of call the member function pointer using the
126  * objectptr as "this", and extracting the remaining arguments from the input
127  * archive. The result will be written to the output archive.
128  *
129  */
130 template <typename T, typename Memfn>
132  static void exec(T* objectptr,
133  comm_server* server,
134  Memfn fn,
135  turi::iarchive& msg,
136  turi::oarchive& response) {
137  typedef typename boost::remove_member_pointer<Memfn>::type fntype;
138  typedef typename function_args_to_tuple<fntype>::type tuple;
139 
140  execute_disect<T, Memfn, tuple>::exec(objectptr, server, fn, msg, response);
141  }
142 };
143 } // namespace detail
144 
145 
146 
147 /**
148  * \internal
149  * \ingroup cppipc
150  * An subclass of the dispatch function which specializes around an object type
151  * and a member function type. To create an instance of the dispatch_impl
152  * use the create_dispatch function.
153  */
154 template <typename T, typename MemFn>
155 struct dispatch_impl: public dispatch {
156  MemFn fn;
157  dispatch_impl(MemFn fn): fn(fn) { }
158 
159  void execute(void* objectptr,
160  comm_server* server,
161  turi::iarchive& msg,
162  turi::oarchive& response) {
163  detail::set_deserializer_to_server(server);
164  detail::execute_disect_call<T, MemFn>::exec((T*)objectptr, server, fn, msg, response);
165  }
166 };
167 
168 /**
169  * \internal
170  * \ingroup cppipc
171  * Creates a dispatch object which wraps a given member function.
172  */
173 template <typename MemFn>
174 dispatch* create_dispatch(MemFn memfn) {
175  typedef typename boost::mpl::at_c<boost::function_types::parameter_types<MemFn>,0>::type Tref;
176  typedef typename std::decay<Tref>::type T;
177  return new dispatch_impl<T, MemFn>(memfn);
178 }
179 } // cppipc
180 #endif
The serialization input archive object which, provided with a reference to an istream, will read from the istream, providing deserialization capabilities.
Definition: iarchive.hpp:60
dispatch * create_dispatch(MemFn memfn)
STL namespace.
The serialization output archive object which, provided with a reference to an ostream, will write to the ostream, providing serialization capabilities.
Definition: oarchive.hpp:80