Turi Create  4.0
magic_macros.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_MAGIC_MACROS_HPP
7 #define CPPIPC_MAGIC_MACROS_HPP
8 #include <core/system/cppipc/ipc_object_base.hpp>
9 #include <core/system/cppipc/registration_macros.hpp>
10 #ifndef DISABLE_TURI_CPPIPC_PROXY_GENERATION
11 #include <core/system/cppipc/server/comm_server.hpp>
12 #include <core/system/cppipc/client/object_proxy.hpp>
13 #include <core/system/cppipc/cppipc.hpp>
14 #endif
15 #include <core/system/cppipc/common/ipc_deserializer.hpp>
16 #include <core/storage/serialization/serialization_includes.hpp>
17 #include <boost/preprocessor.hpp>
18 #define __GENERATE_REGISTRATION__(r, base_name, elem) \
19  REGISTER(base_name::BOOST_PP_TUPLE_ELEM(3,1,elem))
20 
21 
22 #define __GENERATE_PROXY_ARGS__(r, ni, i, elem) elem BOOST_PP_CAT(arg_,i) \
23  BOOST_PP_COMMA_IF(BOOST_PP_GREATER(ni, BOOST_PP_ADD(i, 1)))
24 
25 #define __GENERATE_PROXY_CALL_ARGS__(r, ni, i, elem) BOOST_PP_CAT(arg_,i) \
26  BOOST_PP_COMMA_IF(BOOST_PP_GREATER(ni, BOOST_PP_ADD(i, 1)))
27 
28 
29 #define __GENERATE_BASE__(r, _, elem) \
30  virtual BOOST_PP_TUPLE_ELEM(3, 0, elem) \
31  BOOST_PP_TUPLE_ELEM(3,1, elem) ( \
32  BOOST_PP_SEQ_FOR_EACH_I(__GENERATE_PROXY_ARGS__, \
33  BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3, 2,elem)), \
34  BOOST_PP_TUPLE_ELEM(3,2, elem)) \
35  ) = 0;
36 
37 #define __GENERATE_PROXY_CALLS__(r, base_name, elem) \
38  inline BOOST_PP_TUPLE_ELEM(3, 0, elem) \
39  BOOST_PP_TUPLE_ELEM(3,1, elem) \
40  ( BOOST_PP_SEQ_FOR_EACH_I(__GENERATE_PROXY_ARGS__, \
41  BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3, 2,elem)), \
42  BOOST_PP_TUPLE_ELEM(3,2, elem)) ) { \
43  return proxy.call(&base_name::BOOST_PP_TUPLE_ELEM(3,1,elem) \
44  BOOST_PP_COMMA_IF(BOOST_PP_GREATER(BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3,2,elem)),0)) \
45  BOOST_PP_SEQ_FOR_EACH_I(__GENERATE_PROXY_CALL_ARGS__, \
46  BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3, 2,elem)), \
47  BOOST_PP_TUPLE_ELEM(3, 2, elem)) \
48  ); \
49  }
50 
51 
52 #define __ADD_PAREN_1__(A, B, C) ((A, B, C)) __ADD_PAREN_2__
53 #define __ADD_PAREN_2__(A, B, C) ((A, B, C)) __ADD_PAREN_1__
54 #define __ADD_PAREN_1___END
55 #define __ADD_PAREN_2___END
56 #define __ADD_PARENS__(INPUT) BOOST_PP_CAT(__ADD_PAREN_1__ INPUT,_END)
57 
58 
59 /**
60  * \ingroup cppipc
61  * Magic Interface generating macro.
62  * Like \ref GENERATE_INTERFACE_AND_PROXY but only generates the interface.
63  *
64  * To use, call with the 1st argument as the base name of the interface,
65  * and the 2nd argument as a sequence of:
66  * \code
67  * (return_type, function_name, (arg1type)(arg2type)(arg3type))
68  * \endcode
69  * To get a function with no arguments simply have an empty 3rd argument.
70  * (the 3rd argument is still needed. Observe the comma. It is just empty.)
71  * \code
72  * (return_type, function_name, )
73  * \endcode
74  * For instance,
75  * \code
76  * GENERATE_INTERFACE(object_base, object_proxy,
77  * (std::string, ping, (std::string))
78  * (int, add_one, (int))
79  * (int, add, (int)(int))
80  * )
81  * \endcode
82  * will create a base class called object_base with 3 functions, ping,
83  * add_one, and add, with the appropriate registration functions.
84  *
85  * The above macro generates the following code:
86  * \code
87  * class object_base : public cppipc::ipc_object_base{
88  * public:
89  * typedef object_proxy proxy_object_type;
90  * virtual ~object_base() { }
91  * virtual std::string ping(std::string) = 0;
92  * virtual int add_one(int) = 0;
93  * virtual int add_one(int, int) = 0;
94  *
95  * virtual void save(turi::oarchive& oarc) const {}
96  * virtual void load(turi::iarchive& iarc) {}
97  *
98  * REGISTRATION_BEGIN(test_object_base)
99  * REGISTER(test_object_base::ping)
100  * REGISTER(test_object_base::add)
101  * REGISTER(test_object_base::add_one)
102  * REGISTRATION_END
103  * };
104  * \endcode
105  */
106 #define GENERATE_INTERFACE(base_name, proxy_name, functions) \
107  class base_name : public cppipc::ipc_object_base { \
108  public: \
109  typedef proxy_name proxy_object_type; \
110  inline virtual ~base_name() { } \
111  inline virtual void save(turi::oarchive& oarc) const {} \
112  inline virtual void load(turi::iarchive& iarc) {} \
113  BOOST_PP_SEQ_FOR_EACH(__GENERATE_BASE__, _, __ADD_PARENS__(functions)) \
114  REGISTRATION_BEGIN(base_name) \
115  BOOST_PP_SEQ_FOR_EACH(__GENERATE_REGISTRATION__, base_name, __ADD_PARENS__(functions)) \
116  REGISTRATION_END \
117  };
118 
119 
120 
121 
122 /**
123  * \ingroup cppipc
124  * Magic proxy generating macro.
125  *
126  * Like \ref GENERATE_INTERFACE_AND_PROXY but only generates the proxy.
127  *
128  * To use, call with the 1st argument as the base name of the interface,
129  * the 2nd argument as the name of the proxy class,
130  * and the 3nd argument as a sequence of:
131  * \code
132  * (return_type, function_name, (arg1type)(arg2type)(arg3type))
133  * \endcode
134  * To get a function with no arguments simply have an empty 3rd argument.
135  * (the 3rd argument is still needed. Observe the comma. It is just empty.)
136  * \code
137  * (return_type, function_name, )
138  * \endcode
139  *
140  * For instance,
141  * \code
142  * GENERATE_PROXY(object_base, object_proxy,
143  * (std::string, ping, (std::string))
144  * (int, add_one, (int))
145  * (int, add, (int)(int))
146  * )
147  * \endcode
148  * will create a base class called object_base with 3 functions, ping,
149  * add_one, and add, with the appropriate registration functions, as well as
150  * a proxy object with the appropriate proxy forwarding calls.
151  *
152  * The above macro generates all of the following code:
153  * \code
154  * class object_proxy : public object_base {
155  * public:
156  * cppipc::object_proxy<object_base> proxy;
157  *
158  * inline test_object_proxy(cppipc::comm_client& comm,
159  * bool auto_create = true,
160  * size_t object_id = (size_t)(-1)):
161  * proxy(comm, auto_create, object_id){ }
162  *
163  * inline test_object_proxy(cppipc::comm_client& comm):proxy(comm){ }
164  *
165  * inline std::string ping(std::string arg_0) {
166  * return proxy.call(&object_base::ping, arg_0)
167  * }
168  * inline int add_one(int arg_0) {
169  * return proxy.call(&object_base::add_one, arg_0)
170  * }
171  * inline int add(int arg_0, int arg_1) {
172  * return proxy.call(&object_base::add, arg_0 , arg_1);
173  * }
174  * inline void save(turi::oarchive& oarc) const {
175  * oarc << proxy.get_object_id();
176  * }
177  * inline void load(turi::iarchive& iarc) {
178  * size_t objid; iarc >> objid;
179  * proxy.set_object_id(objid);
180  * }
181  * };
182  * \endcode
183  */
184 #define GENERATE_PROXY(base_name, proxy_name, functions) \
185  class proxy_name : public base_name { \
186  public: \
187  cppipc::object_proxy<base_name> proxy; \
188  inline proxy_name(cppipc::comm_client& comm, \
189  bool auto_create = true, \
190  size_t object_id = (size_t)(-1)): \
191  proxy(comm, auto_create, object_id){ } \
192  inline void save(turi::oarchive& oarc) const { \
193  oarc << proxy.get_object_id(); \
194  } \
195  inline size_t __get_object_id() const { \
196  return proxy.get_object_id(); \
197  } \
198  inline void load(turi::iarchive& iarc) { \
199  size_t objid; iarc >> objid; \
200  proxy.set_object_id(objid); \
201  } \
202  BOOST_PP_SEQ_FOR_EACH(__GENERATE_PROXY_CALLS__, base_name, __ADD_PARENS__(functions)) \
203  };
204 
205 
206 
207 /**
208  * \ingroup cppipc
209  * Magic Interface and proxy generating macro.
210  *
211  * To use, call with the 1st argument as the base name of the interface,
212  * the 2nd argument as the name of the proxy class,
213  * and the 3nd argument as a sequence of:
214  * \code
215  * (return_type, function_name, (arg1type)(arg2type)(arg3type))
216  * \endcode
217  * To get a function with no arguments simply have an empty 3rd argument.
218  * (the 3rd argument is still needed. Observe the comma. It is just empty.)
219  * \code
220  * (return_type, function_name, )
221  * \endcode
222  *
223  * For instance,
224  * \code
225  * GENERATE_INTERFACE_AND_PROXY(object_base, object_proxy,
226  * (std::string, ping, (std::string))
227  * (int, add_one, (int))
228  * (int, add, (int)(int))
229  * )
230  * \endcode
231  * will create a base class called object_base with 3 functions, ping,
232  * add_one, and add, with the appropriate registration functions, as well as
233  * a proxy object with the appropriate proxy forwarding calls.
234  *
235  * The above macro generates all of the following code:
236  * \code
237  * class proxy_object_type;
238  * class object_base : public cppipc::ipc_object_base {
239  * public:
240  * typedef object_proxy proxy_object_type;
241  * virtual inline ~object_base() { }
242  * virtual std::string ping(std::string) = 0;
243  * virtual int add_one(int) = 0;
244  * virtual int add_one(int, int) = 0;
245  *
246  * virtual void save(turi::oarchive& oarc) const {}
247  * virtual void load(turi::iarchive& iarc) {}
248  *
249  * REGISTRATION_BEGIN(test_object_base)
250  * REGISTER(test_object_base::ping)
251  * REGISTER(test_object_base::add)
252  * REGISTER(test_object_base::add_one)
253  * REGISTRATION_END
254  * };
255  *
256  * class object_proxy : public object_base {
257  * public:
258  * cppipc::object_proxy<object_base> proxy;
259  *
260  * inline test_object_proxy(cppipc::comm_client& comm,
261  * bool auto_create = true,
262  * size_t object_id = (size_t)(-1)):
263  * proxy(comm, auto_create, object_id){ }
264  *
265  * inline std::string ping(std::string arg_0) {
266  * return proxy.call(&object_base::ping, arg_0)
267  * }
268  * inline int add_one(int arg_0) {
269  * return proxy.call(&object_base::add_one, arg_0)
270  * }
271  * inline int add(int arg_0, int arg_1) {
272  * return proxy.call(&object_base::add, arg_0 , arg_1);
273  * }
274  * inline void save(turi::oarchive& oarc) const {
275  * oarc << proxy.get_object_id();
276  * }
277  * inline void load(turi::iarchive& iarc) {
278  * size_t objid; iarc >> objid;
279  * proxy.set_object_id(objid);
280  * }
281  * };
282  * \endcode
283  */
284 
285 #ifdef DISABLE_TURI_CPPIPC_PROXY_GENERATION
286 
287 #define GENERATE_INTERFACE_AND_PROXY(base_name, proxy_name, functions) \
288  class proxy_name; \
289  GENERATE_INTERFACE(base_name, proxy_name, functions)
290 
291 #else
292 
293 #define GENERATE_INTERFACE_AND_PROXY(base_name, proxy_name, functions) \
294  class proxy_name; \
295  GENERATE_INTERFACE(base_name, proxy_name, functions) \
296  GENERATE_PROXY(base_name, proxy_name, functions)
297 
298 #endif
299 
300 #endif