Turi Create  4.0
object_proxy.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_CLIENT_CLIENT_HPP
7 #define CPPIPC_CLIENT_CLIENT_HPP
8 #include <string>
9 #include <map>
10 #include <core/system/cppipc/client/comm_client.hpp>
11 namespace cppipc {
12 
13 
14 /**
15  * \ingroup cppipc
16  * Refers to a remote object and allows function calls to be issued
17  * across a communication link.
18  *
19  * The object_proxy object internally maintains an object ID which identifies
20  * an object on the other side of a communication link established by the
21  * comm_client. The object_proxy is templatized over a type T which must have
22  * an identical object interface as the remote object. T must also provide the
23  * registration callbacks which match the registration callbacks on the remote
24  * end. For that reason, it is easiest if T defines an interface and implements
25  * the register callbacks. And the remote object then inherits from T.
26  *
27  * The recommended pattern is as follows:
28  * Given the following base class with an implementation on the server side
29  *
30  * \code
31  * class object_base {
32  * public:
33  * virtual ~object_base() { }
34  * virtual int add(int, int) = 0;
35  * };
36  * \endcode
37  *
38  * We implement a proxy object which has the object_proxy as a member, and
39  * inherits from the object_base. Each function call is then forwarded to
40  * the remote machine.
41  *
42  * \code
43  * class object_proxy: public object_base {
44  * public:
45  * cppipc::object_proxy<object_base> proxy;
46  *
47  * // proxy must be provided with the comm_client object on construction
48  * test_object_proxy(cppipc::comm_client& comm):proxy(comm){ }
49  *
50  * int add(int a, int b) {
51  * // forward the call to the remote machine
52  * return proxy.call(&object_base::add,a, b);
53  * }
54  * };
55  * \endcode
56  */
57 template <typename T>
58 class object_proxy {
59  public:
60  /**
61  * Creates an object_proxy object using the communication client provided
62  * for communication. If auto_create is set to true, a new remote object
63  * is created on the remote machine. Otherwise, no remote object ID is
64  * specified, and set_object_id() must be called to set the remote object ID.
65  *
66  * \param comm The comm client object to use for communication
67  * \param auto_create If true, will create the remote object on
68  * construction of the object proxy.
69  * \param object_id The object ID to use in the proxy. Only valid when
70  * auto_create is false.
71  */
73  bool auto_create = true,
74  size_t object_id = (size_t)(-1)):
75  comm(comm),
76  remote_object_id(object_id) {
77  T::__register__(comm);
78  if (auto_create) remote_object_id = comm.make_object(T::__get_type_name__());
79 
80  // Increase reference count of this object
81  size_t ref_cnt = comm.incr_ref_count(remote_object_id);
82  if(ref_cnt == 0) {
83  // Shouldn't ever happen
84  throw ipcexception(reply_status::EXCEPTION,
85  0,
86  "Object not tracked after increasing ref count!");
87  }
88  }
89 
90  ~object_proxy() {
91  remote_delete();
92  }
93 
94  /**
95  * Deletes the remote object referred to by this proxy.
96  * The object ID in the proxy will be cleared.
97  */
98  void remote_delete() {
99  if (remote_object_id != (size_t)(-1)) {
100  comm.decr_ref_count(remote_object_id);
101  }
102  remote_object_id = (size_t)(-1);
103  }
104 
105  /**
106  * Assigns the object ID managed by this proxy.
107  */
108  void set_object_id(size_t object_id) {
109  comm.decr_ref_count(remote_object_id);
110  comm.incr_ref_count(object_id);
111  remote_object_id = object_id;
112  }
113  /**
114  * Gets the object ID managed by this proxy.
115  */
116  size_t get_object_id() const {
117  return remote_object_id;
118  }
119 
120  /**
121  * Returns a reference to the communication object used.
122  */
123  inline comm_client& get_comm() {
124  return comm;
125  }
126 
127  /// \internal do not use
128  template <typename S>
129  void register_object(S* object) {
130  // do nothing
131  }
132 
133  /**
134  * \internal do not use
135  * Registers a member function of T, associating it with a string name
136  */
137  template <typename MemFn>
138  void register_function(MemFn f, std::string function_string) {
139  comm.register_function(f, function_string);
140  }
141 
142  /**
143  * Calls a remote function returning the result.
144  * The remote function's return is forwarded and returned here.
145  * An exception is raised of type reply_status if there is an error.
146  */
147  template <typename MemFn, typename... Args>
148  typename detail::member_function_return_type<MemFn>::type
149  call(MemFn f, const Args&... args) {
150  return comm.call(remote_object_id, f, args...);
151  }
152 
153  private:
154  comm_client& comm;
155  size_t remote_object_id;
156 };
157 
158 
159 } // cppipc
160 #endif
Other general exception. Body will contain the exception message.
size_t make_object(std::string object_type_name)
detail::member_function_return_type< MemFn >::type call(size_t objectid, MemFn f, const Args &... args)
size_t get_object_id() const
comm_client & get_comm()
void register_function(MemFn f, std::string function_string)
void register_object(S *object)
object_proxy(comm_client &comm, bool auto_create=true, size_t object_id=(size_t)(-1))
void set_object_id(size_t object_id)
detail::member_function_return_type< MemFn >::type call(MemFn f, const Args &... args)
void register_function(MemFn f, std::string function_string)
size_t incr_ref_count(size_t object_id)