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