Remote Call Framework 3.1
Future.hpp
1 
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2019, Delta V Software. All rights reserved.
6 // http://www.deltavsoft.com
7 //
8 // RCF is distributed under dual licenses - closed source or GPL.
9 // Consult your particular license for conditions of use.
10 //
11 // If you have not purchased a commercial license, you are using RCF
12 // under GPL terms.
13 //
14 // Version: 3.1
15 // Contact: support <at> deltavsoft.com
16 //
17 //******************************************************************************
18 
19 #ifndef INCLUDE_RCF_FUTURE_HPP
20 #define INCLUDE_RCF_FUTURE_HPP
21 
22 #include <RCF/ClientStub.hpp>
23 #include <RCF/Marshal.hpp>
24 
25 namespace RCF {
26 
27  class I_Future
28  {
29  public:
30  virtual ~I_Future() {}
31  virtual void setClientStub(ClientStub *pClientStub) = 0;
32  };
33 
34  template<typename T>
36 
38 
42 
47 
49 
50  template<typename T>
51  class Future
52  {
53  public:
54 
56  Future() : mStatePtr(new State())
57  {}
58 
59  Future(T *pt) : mStatePtr( new State(pt))
60  {}
61 
62  Future(T *pt, ClientStub *pClientStub) : mStatePtr( new State(pt))
63  {
64  pClientStub->enrol(mStatePtr.get());
65  }
66 
68  Future(const T &t) : mStatePtr( new State(t))
69  {}
70 
71  operator T&()
72  {
73  return mStatePtr->operator T&();
74  }
75 
77  T& operator*()
78  {
79  return mStatePtr->operator T&();
80  }
81 
82  Future &operator=(const Future &rhs)
83  {
84  mStatePtr = rhs.mStatePtr;
85  return *this;
86  }
87 
88  Future &operator=(const FutureConverter<T> &rhs)
89  {
90  rhs.assignTo(*this);
91  return *this;
92  }
93 
94  Future(const FutureConverter<T> &rhs) : mStatePtr( new State())
95  {
96  rhs.assignTo(*this);
97  }
98 
100  bool ready()
101  {
102  return mStatePtr->ready();
103  }
104 
106  void wait(std::uint32_t timeoutMs = 0)
107  {
108  mStatePtr->wait(timeoutMs);
109  }
110 
112  void cancel()
113  {
114  mStatePtr->cancel();
115  }
116 
118  void clear()
119  {
120  mStatePtr->clear();
121  }
122 
123  ClientStub & getClientStub()
124  {
125  return mStatePtr->getClientStub();
126  }
127 
128  // Retrieves the exception, if any, returned by an asynchronous call.
129  std::unique_ptr<Exception> getAsyncException()
130  {
131  return mStatePtr->getClientStub().getAsyncException();
132  }
133 
134  private:
135 
136  template<typename U>
137  friend class FutureConverter;
138 
139  class State : public I_Future, Noncopyable
140  {
141  public:
142  State() :
143  mpt(),
144  mtPtr( new T() ),
145  mpClientStub()
146  {}
147 
148  State(T *pt) :
149  mpt(pt),
150  mpClientStub()
151  {}
152 
153  State(const T &t) :
154  mpt(),
155  mtPtr( new T(t) ),
156  mpClientStub()
157  {}
158 
159  ~State()
160  {
161  RCF_DTOR_BEGIN
162  unregisterFromCandidates();
163  RCF_DTOR_END
164  }
165 
166  operator T&()
167  {
168  // If a call has been made, check that it has completed, and
169  // that there was no exception.
170 
171  if (mpClientStub)
172  {
173  if (!mpClientStub->ready())
174  {
175  mpClientStub->waitForReady();
176  }
177 
178  std::unique_ptr<Exception> ePtr =
179  mpClientStub->getAsyncException();
180 
181  if (ePtr.get())
182  {
183  ePtr->throwSelf();
184  }
185  }
186 
187  T *pt = mpt ? mpt : mtPtr.get();
188  {
189  Lock lock(gCandidatesMutex());
190  gCandidates().add(pt, this);
191  }
192 
193  return *pt;
194  }
195 
196  void setClientStub(ClientStub *pClientStub)
197  {
198  mpClientStub = pClientStub;
199  }
200 
201  void setClientStub(ClientStub *pClientStub, T * pt)
202  {
203  unregisterFromCandidates();
204 
205  mpClientStub = pClientStub;
206  mpt = pt;
207  mtPtr.reset();
208  }
209 
210  private:
211 
212  T * mpt;
213  std::unique_ptr<T> mtPtr;
214  RCF::ClientStub * mpClientStub;
215 
216  public:
217 
218  bool ready()
219  {
220  return mpClientStub->ready();
221  }
222 
223  void wait(std::uint32_t timeoutMs = 0)
224  {
225  mpClientStub->waitForReady(timeoutMs);
226  }
227 
228  void cancel()
229  {
230  mpClientStub->cancel();
231  }
232 
233  ClientStub & getClientStub()
234  {
235  return *mpClientStub;
236  }
237 
238  void unregisterFromCandidates()
239  {
240  T *pt = mpt ? mpt : mtPtr.get();
241  Lock lock(gCandidatesMutex());
242  I_Future * pFuture = gCandidates().find(pt);
243  if (pFuture)
244  {
245  gCandidates().erase(pt);
246  }
247  }
248 
249  };
250 
251  std::shared_ptr<State> mStatePtr;
252  };
253 
254  class LogEntryExit
255  {
256  public:
257  LogEntryExit(ClientStub & clientStub);
258  ~LogEntryExit();
259 
260  private:
261  ClientStub & mClientStub;
262  const std::string & mMsg;
263  };
264 
265  // Base class for FutureConverter<>.
266  class RCF_EXPORT FutureConverterBase
267  {
268  protected:
269 
270  FutureConverterBase(
271  ClientStub &clientStub,
272  int fnId,
273  RemoteCallMode rcs,
274  const char * szFunc,
275  const char * szArity);
276 
277  FutureConverterBase(const FutureConverterBase& rhs);
278  FutureConverterBase &operator=(const FutureConverterBase &rhs);
279 
280  void call() const;
281  void callSync() const;
282  void callAsync() const;
283 
284  ClientStub * mpClientStub;
285  int mFnId;
286  RemoteCallMode mRcs;
287  const char * mSzFunc;
288  const char * mSzArity;
289  mutable bool mOwn;
290  };
291 
293 
296  template<typename T>
297  class FutureConverter : public FutureConverterBase
298  {
299  public:
301  T &t,
302  ClientStub &clientStub,
303  int fnId,
304  RemoteCallMode rcs,
305  const char * szFunc = "",
306  const char * szArity = "") :
307  FutureConverterBase(clientStub, fnId, rcs, szFunc, szArity),
308  mpT(&t)
309  {
310  }
311 
312  FutureConverter(const FutureConverter &rhs) :
313  FutureConverterBase(rhs),
314  mpT(rhs.mpT)
315  {
316  }
317 
318  FutureConverter &operator=(const FutureConverter &rhs)
319  {
320  FutureConverterBase::operator=(rhs);
321  mpT = rhs.mpT;
322  return *this;
323  }
324 
325  T get()
326  {
327  return operator T();
328  }
329 
330  // Conversion to T kicks off a sync call.
331  operator T() const
332  {
333  mOwn = false;
334  call();
335  T t = *mpT;
336  mpClientStub->clearParameters();
337  return t;
338  }
339 
340  // Assignment to Future<> kicks off an async call.
341  void assignTo(Future<T> &future) const
342  {
343  mOwn = false;
344  mpClientStub->setAsync(true);
345  future.mStatePtr->setClientStub(mpClientStub, mpT);
346  call();
347  }
348 
349  // Void or ignored return value, kicks off a sync call.
350  ~FutureConverter() RCF_DTOR_THROWS
351  {
352  if(mOwn)
353  {
354  call();
355 
356  if (!mpClientStub->getAsync())
357  {
358  mpClientStub->clearParameters();
359  }
360  }
361  }
362 
363  private:
364  T * mpT;
365  };
366 
367  template<typename T, typename U>
368  bool operator==(const FutureConverter<T> & fi, const U & u)
369  {
370  return fi.operator T() == u;
371  }
372 
373  template<typename T, typename U>
374  bool operator==(const U & u, const FutureConverter<T> & fi)
375  {
376  return u == fi.operator T();
377  }
378 
379 
380 }
381 
382 #endif // INCLUDE_RCF_FUTURE_HPP
bool ready()
Tests whether the result of an asynchronous call is ready.
Definition: Future.hpp:100
Controls the client side of a RCF connection.
Definition: ClientStub.hpp:82
void waitForReady(std::uint32_t timeoutMs=0)
Waits until an asynchronous call is ready.
Future()
Constructs a new Future instance.
Definition: Future.hpp:56
void cancel()
Cancels an asynchronous call.
std::unique_ptr< Exception > getAsyncException()
Retrieves an asynchronous exception.
void wait(std::uint32_t timeoutMs=0)
Waits for up to timeoutMs ms, for the result of an asynchronous call to become ready.
Definition: Future.hpp:106
RemoteCallMode
Remote call mode.
Definition: Enums.hpp:141
Provides the ability for remote calls to be executed asynchronously.
Definition: Future.hpp:51
void cancel()
Cancels an asynchronous call.
Definition: Future.hpp:112
T & operator*()
Dereferences this Future instance. If the remote call is still in progress, this function will block ...
Definition: Future.hpp:77
Utility class used by RCF to determine whether a remote call should be performed synchronously or asy...
Definition: Future.hpp:35
bool ready()
Returns true if an asynchronous call is ready.
void clear()
Clears this Future instance.
Definition: Future.hpp:118
Definition: AmiIoHandler.hpp:24
Future(const T &t)
Constructs a new Future instance, holding a copy of t.
Definition: Future.hpp:68