libqi-api  2.4.3.28
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
future.hxx
Go to the documentation of this file.
1 #pragma once
2 /*
3 ** Copyright (C) 2012 Aldebaran Robotics
4 ** See COPYING for the license
5 */
6 
7 #ifndef _QI_DETAILS_FUTURE_HXX_
8 #define _QI_DETAILS_FUTURE_HXX_
9 
10 #include <vector>
11 #include <utility> // pair
12 #include <boost/bind.hpp>
13 #include <qi/eventloop.hpp>
14 #include <qi/actor.hpp>
15 #include <qi/anyvalue.hpp>
17 #include <qi/log.hpp>
18 
19 namespace qi {
20 
21 namespace detail {
22 
23  template <typename T, typename R>
24  struct Caller
25  {
26  inline static R _callfunc(const T& arg,
27  const boost::function<R(const T&)>& func)
28  {
29  return func(arg);
30  }
31  };
32 
33  template <typename T>
34  struct Caller<T, void>
35  {
36  inline static void* _callfunc(const T& future,
37  const boost::function<void(const T&)>& func)
38  {
39  func(future);
40  return 0;
41  }
42  };
43 
44  template <typename T, typename R>
45  void continuateThen(const Future<T>& future,
46  const boost::function<R(const Future<T>&)>& func,
47  qi::Promise<R>& promise)
48  {
49  try
50  {
51  promise.setValue(Caller<Future<T>, R>::_callfunc(future, func));
52  }
53  catch (std::exception& e)
54  {
55  promise.setError(e.what());
56  }
57  catch (...)
58  {
59  promise.setError("unknown exception");
60  }
61  }
62 
63  template <typename T, typename R>
64  void continuateAndThen(const Future<T>& future,
65  const boost::function<R(const typename Future<T>::ValueType&)>& func,
66  qi::Promise<R>& promise)
67  {
68  if (future.isCanceled())
69  promise.setCanceled();
70  else if (future.hasError())
71  promise.setError(future.error());
72  else if (promise.isCancelRequested())
73  promise.setCanceled();
74  else
75  {
76  try
77  {
78  promise.setValue(Caller<T, R>::_callfunc(future.value(), func));
79  }
80  catch (std::exception& e)
81  {
82  promise.setError(e.what());
83  }
84  catch (...)
85  {
86  promise.setError("unknown exception");
87  }
88  }
89  }
90 
91  template <typename T>
92  inline void forwardCancel(
93  const boost::weak_ptr<FutureBaseTyped<T> >& wfutureb)
94  {
95  boost::shared_ptr<FutureBaseTyped<T> > futureb = wfutureb.lock();
96  if (!futureb)
97  return;
98  Future<T>(futureb).cancel();
99  }
100 
101 } // namespace detail
102 
103  template <typename T>
104  template <typename R>
106  FutureCallbackType type,
107  const boost::function<R(const Future<T>&)>& func)
108  {
109  qi::Promise<R> promise(
110  this->isCancelable()
111  ? boost::bind(&detail::forwardCancel<T>,
112  boost::weak_ptr<detail::FutureBaseTyped<T> >(_p))
113  : boost::function<void(qi::Promise<R>)>());
114  _p->connect(*this, boost::bind(&detail::continuateThen<T, R>, _1,
115  func, promise), type);
116  return promise.future();
117  }
118 
119  template <typename T>
120  template <typename R>
122  FutureCallbackType type,
123  const boost::function<R(const typename Future<T>::ValueType&)>& func)
124  {
125  qi::Promise<R> promise(
126  this->isCancelable()
127  ? boost::bind(&detail::forwardCancel<T>,
128  boost::weak_ptr<detail::FutureBaseTyped<T> >(_p))
129  // if the future is not cancelable, now it becomes cancelable because
130  // continuateAndThen will abort if cancel is requested
131  : boost::function<void(qi::Promise<T>&)>(&qi::PromiseNoop<R>));
132  _p->connect(*this, boost::bind(&detail::continuateAndThen<T, R>, _1,
133  func, promise), type);
134  return promise.future();
135  }
136 
137  template <typename T>
138  template <typename Arg>
139  inline void Future<T>::binder(
140  const boost::function<void(const boost::function<void()>&)>& poster,
141  const boost::function<void(const Arg&)>& callback, const Arg& fut)
142  {
143  return poster(boost::bind(callback, fut));
144  }
145 
146  template <typename T>
147  template <typename Arg>
148  inline boost::function<void(const Arg&)>
149  Future<T>::transformStrandedCallback(
150  qi::Strand* strand,
151  const boost::function<void(const Arg&)>& cb)
152  {
153  return boost::bind(
154  &Future<T>::binder<Arg>,
155  boost::function<void(const boost::function<void()>&)>(
156  boost::bind(
158  strand, _1)),
159  cb, _1);
160  }
161 
162  template <typename T>
163  template <typename ARG0>
164  inline typename boost::enable_if<
165  boost::is_base_of<Actor, typename detail::Unwrap<ARG0>::type>,
166  void>::type
167  Future<T>::_connectMaybeActor(
168  const ARG0& arg0, const boost::function<void(const Future<T>&)>& cb,
169  FutureCallbackType type)
170  {
171  _p->connect(*this,
173  boost::function<void()>(),
174  transformStrandedCallback<qi::Future<T> >(
175  detail::Unwrap<ARG0>::unwrap(arg0)->strand(), cb),
176  arg0),
178  }
179  template <typename T>
180  template <typename ARG0>
181  inline typename boost::disable_if<
182  boost::is_base_of<Actor, typename detail::Unwrap<ARG0>::type>,
183  void>::type
184  Future<T>::_connectMaybeActor(
185  const ARG0& arg0, const boost::function<void(const Future<T>&)>& cb,
186  FutureCallbackType type)
187  {
188  _p->connect(*this, cb, type);
189  }
190 
191  template <typename T>
192  template <typename R, typename ARG0, typename AF>
193  typename boost::enable_if<
194  boost::is_base_of<Actor, typename detail::Unwrap<ARG0>::type>,
195  qi::Future<R> >::type
196  Future<T>::_thenMaybeActor(const ARG0& arg0,
197  const AF& cb,
198  FutureCallbackType type)
199  {
201  boost::function<void()>(),
202  transformStrandedCallback<typename qi::Future<T>::ValueType>(
203  detail::Unwrap<ARG0>::unwrap(arg0)->strand(), cb),
204  arg0));
205  }
206  template <typename T>
207  template <typename R, typename ARG0, typename AF>
208  typename boost::disable_if<
209  boost::is_base_of<Actor, typename detail::Unwrap<ARG0>::type>,
210  qi::Future<R> >::type
211  Future<T>::_thenMaybeActor(const ARG0& arg0,
212  const AF& cb,
213  FutureCallbackType type)
214  {
215  return thenR(type, cb);
216  }
217 
218  template <typename T>
219  void Future<T>::_weakCancelCb(const boost::weak_ptr<detail::FutureBaseTyped<T> >& wfuture)
220  {
221  if (boost::shared_ptr<detail::FutureBaseTyped<T> > fbt = wfuture.lock())
222  {
223  Future<T> future(fbt);
224  assert(future.isCancelable());
225  future.cancel();
226  }
227  }
228 
229  template <typename T>
230  boost::function<void()> Future<T>::makeCanceler()
231  {
232  if (!isCancelable())
233  throw std::runtime_error("future is not cancelable");
234  return boost::bind(&Future<T>::_weakCancelCb, boost::weak_ptr<detail::FutureBaseTyped<T> >(_p));
235  }
236 
237  namespace detail {
238 
239  class FutureBasePrivate;
241  public:
242  FutureBase();
243  ~FutureBase();
244 
245  FutureState wait(int msecs) const;
246  FutureState wait(qi::Duration duration) const;
247  FutureState wait(qi::SteadyClock::time_point timepoint) const;
248  FutureState state() const;
249  bool isRunning() const;
250  bool isFinished() const;
251  bool isCanceled() const;
252  bool isCancelRequested() const;
253  bool hasError(int msecs) const;
254  bool hasValue(int msecs) const;
255  const std::string &error(int msecs) const;
256  void reportStart();
257  void reset();
258 
259  protected:
260  void reportValue();
261  void reportError(const std::string &message);
262  void requestCancel();
263  void reportCanceled();
264  boost::recursive_mutex& mutex();
265  void notifyFinish();
266 
267  public:
268  FutureBasePrivate *_p;
269  };
270 
271 
272  //common state shared between a Promise and multiple Futures
273  template <typename T>
274  class FutureBaseTyped : public FutureBase {
275  public:
276  typedef boost::function<void(Promise<T>)> CancelCallback;
277  typedef typename FutureType<T>::type ValueType;
279  : _value()
280  , _async(FutureCallbackType_Async)
281  {
282  }
283 
285  {
286  if (_onDestroyed && hasValue(0))
287  _onDestroyed(_value);
288  }
289 
290  bool isCancelable() const
291  {
292  return static_cast<bool>(_onCancel);
293  }
294 
295  void cancel(qi::Future<T>& future)
296  {
297  CancelCallback onCancel;
298  {
299  boost::recursive_mutex::scoped_lock lock(mutex());
300  if (isFinished())
301  return;
302  if (!_onCancel)
304  requestCancel();
305  onCancel = _onCancel;
306  }
307  onCancel(Promise<T>(future));
308  }
309 
311  CancelCallback onCancel)
312  {
313  bool doCancel = false;
314  {
315  boost::recursive_mutex::scoped_lock lock(mutex());
316  _onCancel = onCancel;
317  doCancel = isCancelRequested();
318  }
319  qi::Future<T> fut = promise.future();
320  if (doCancel)
321  cancel(fut);
322  }
323 
325  {
326  for(unsigned i = 0; i<_onResult.size(); ++i)
327  {
328  try {
329  if (_async == FutureCallbackType_Async)
330  getEventLoop()->post(boost::bind(_onResult[i], future));
331  else
332  _onResult[i](future);
333  } catch(const qi::PointerLockException&) { // do nothing
334  } catch(const std::exception& e) {
335  qiLogError("qi.future") << "Exception caught in future callback "
336  << e.what();
337  } catch (...) {
338  qiLogError("qi.future")
339  << "Unknown exception caught in future callback";
340  }
341  }
342  notifyFinish();
343  clearCallbacks();
344  }
345 
346  void setValue(qi::Future<T>& future, const ValueType &value)
347  {
348  // report-ready + onResult() must be Atomic to avoid
349  // missing callbacks/double calls in case connect() is invoked at
350  // the same time
351  boost::recursive_mutex::scoped_lock lock(mutex());
352  if (!isRunning())
354 
355  _value = value;
356  reportValue();
357  callCbNotify(future);
358  }
359 
360  /*
361  * inplace api for promise
362  */
363  void set(qi::Future<T>& future)
364  {
365  // report-ready + onResult() must be Atomic to avoid
366  // missing callbacks/double calls in case connect() is invoked at
367  // the same time
368  boost::recursive_mutex::scoped_lock lock(mutex());
369  if (!isRunning())
371 
372  reportValue();
373  callCbNotify(future);
374  }
375 
376  void setError(qi::Future<T>& future, const std::string &message)
377  {
378  boost::recursive_mutex::scoped_lock lock(mutex());
379  if (!isRunning())
381 
382  reportError(message);
383  callCbNotify(future);
384  }
385 
386  void setBroken(qi::Future<T>& future)
387  {
388  boost::recursive_mutex::scoped_lock lock(mutex());
389  assert(isRunning());
390 
391  reportError("Promise broken (all promises are destroyed)");
392  callCbNotify(future);
393  }
394 
395  void setCanceled(qi::Future<T>& future) {
396  boost::recursive_mutex::scoped_lock lock(mutex());
397  if (!isRunning())
399 
400  reportCanceled();
401  callCbNotify(future);
402  }
403 
404  void setOnDestroyed(boost::function<void (ValueType)> f)
405  {
406  _onDestroyed = f;
407  }
408 
409  void connect(qi::Future<T> future,
410  const boost::function<void (qi::Future<T>)> &s,
411  FutureCallbackType type)
412  {
413  bool ready;
414  {
415  boost::recursive_mutex::scoped_lock lock(mutex());
416  ready = isFinished();
417  if (!ready)
418  {
419  _onResult.push_back(s);
420  }
421  }
422  //result already ready, notify the callback
423  if (ready) {
424  if (type == FutureCallbackType_Async)
425  {
426  getEventLoop()->post(boost::bind(s, future));
427  }
428  else
429  {
430  try {
431  s(future);
432  } catch(const ::qi::PointerLockException&)
433  {/*do nothing*/}
434  }
435  }
436  }
437 
438  const ValueType &value(int msecs) const {
439  FutureState state = wait(msecs);
440  if (state == FutureState_Running)
442  if (state == FutureState_Canceled)
444  if (state == FutureState_FinishedWithError)
446  return _value;
447  }
448 
449  private:
450  friend class Promise<T>;
451  typedef std::vector<boost::function<void (qi::Future<T>)> > Callbacks;
452  Callbacks _onResult;
453  ValueType _value;
454  CancelCallback _onCancel;
455  boost::function<void (ValueType)> _onDestroyed;
456  FutureCallbackType _async;
457  qi::Atomic<unsigned int> _promiseCount;
458 
459  void clearCallbacks()
460  {
461  _onResult.clear();
462  if (_onCancel)
463  {
464  _onCancel = CancelCallback(PromiseNoop<T>);
465  }
466  }
467  };
468 
469  template <typename T>
471  qi::Future<T>& fut,
472  qi::Atomic<int>* count) {
473  if (!prom.future().isFinished() && !fut.hasError())
474  {
475  // An other future can trigger at the same time.
476  // Don't bother to lock, just catch the FutureAlreadySet exception
477  try
478  {
479  prom.setValue(fut);
480  }
481  catch(const FutureException&)
482  {}
483  }
484  if (! --*count)
485  {
486  // I'm the last
487  if (!prom.future().isFinished())
488  {
489  // same 'race' as above. between two setError, not between a value and
490  // an error.
491  try
492  {
493  prom.setValue(makeFutureError<T>("No future returned successfully."));
494  }
495  catch(const FutureException&)
496  {}
497  }
498  delete count;
499  }
500  }
501 
502  template <typename T>
503  class AddUnwrap<Future<T> >
504  {
505  public:
507  {
508  Future<Future<T> >* self = static_cast<Future<Future<T> >*>(this);
509 
510  Promise<T> promise(boost::bind(&AddUnwrap<Future<T> >::_cancel, _1,
511  boost::weak_ptr<FutureBaseTyped<Future<T> > >(self->_p)));
512 
513  self->connect(
514  boost::bind(&AddUnwrap<Future<T> >::_forward, _1, promise),
516 
517  return promise.future();
518  }
519 
520  private:
521  static void _forward(const Future<Future<T> >& future,
522  Promise<T>& promise)
523  {
524  if (future.isCanceled())
525  promise.setCanceled();
526  else if (future.hasError())
527  promise.setError(future.error());
528  else
529  adaptFuture(future.value(), promise);
530  }
531 
532  static void _cancel(Promise<T>& promise,
533  const boost::weak_ptr<FutureBaseTyped<Future<T> > >& wfuture)
534  {
535  if (boost::shared_ptr<FutureBaseTyped<Future<T> > > fbt =
536  wfuture.lock())
537  {
538  Future<Future<T> > future(fbt);
539  if (future.isCancelable())
540  future.cancel();
541  }
542  }
543  };
544 
545  } // namespace detail
546 
547  template <typename T>
548  qi::Future<T> makeFutureError(const std::string &error) {
549  qi::Promise<T> prom;
550  prom.setError(error);
551  return prom.future();
552  }
553 
554  namespace detail
555  {
556  template<typename FT, typename PT, typename CONV>
557  void futureAdapter(Future<FT> f, Promise<PT> p, CONV converter)
558  {
559  if (f.hasError())
560  p.setError(f.error());
561  else if (f.isCanceled())
562  p.setCanceled();
563  else
564  {
565  try {
566  converter(f.value(), p.value());
567  }
568  catch (const std::exception& e)
569  {
570  p.setError(std::string("futureAdapter conversion error: ") + e.what());
571  return;
572  }
573  p.trigger();
574  }
575  }
576 
577  template<typename FT>
578  void futureCancelAdapter(boost::weak_ptr<FutureBaseTyped<FT> > wf)
579  {
580  if (boost::shared_ptr<FutureBaseTyped<FT> > f = wf.lock())
581  Future<FT>(f).cancel();
582  }
583  }
584 
585  template <>
586  struct FutureValueConverter<void, void>
587  {
588  void operator()(void* in, void* out)
589  {
590  }
591  };
592 
593  template <typename T>
594  struct FutureValueConverter<T, void>
595  {
596  void operator()(const T& in, void* out)
597  {
598  }
599  };
600 
601  template <typename T>
602  struct FutureValueConverter<void, T>
603  {
604  void operator()(void* in, const T& out)
605  {
606  }
607  };
608 
609  template<typename R>
611  {
612  if (f.isCancelable())
613  p.setup(boost::bind(&detail::futureCancelAdapter<AnyReference>,
614  boost::weak_ptr<detail::FutureBaseTyped<AnyReference> >(f._p)));
615  f.connect(boost::function<void(qi::Future<AnyReference>&)>(
616  boost::bind(&detail::futureAdapter<R>, _1, p)),
618  }
619 
620  template<typename FT, typename PT>
621  void adaptFuture(const Future<FT>& f, Promise<PT>& p)
622  {
623  if (f.isCancelable())
624  p.setup(boost::bind(&detail::futureCancelAdapter<FT>,
625  boost::weak_ptr<detail::FutureBaseTyped<FT> >(f._p)));
626  const_cast<Future<FT>&>(f).connect(boost::bind(detail::futureAdapter<FT, PT, FutureValueConverter<FT, PT> >, _1, p,
628  }
629 
630  template<typename FT, typename PT, typename CONV>
631  void adaptFuture(const Future<FT>& f, Promise<PT>& p, CONV converter)
632  {
633  if (f.isCancelable())
634  p.setup(boost::bind(&detail::futureCancelAdapter<FT>,
635  boost::weak_ptr<detail::FutureBaseTyped<FT> >(f._p)));
636  const_cast<Future<FT>&>(f).connect(boost::bind(detail::futureAdapter<FT, PT, CONV>, _1, p, converter), FutureCallbackType_Sync);
637  }
638 }
639 
641 
642 #endif // _QI_DETAILS_FUTURE_HXX_
static void * _callfunc(const T &future, const boost::function< void(const T &)> &func)
Definition: future.hxx:36
void setError(qi::Future< T > &future, const std::string &message)
Definition: future.hxx:376
void forwardCancel(const boost::weak_ptr< FutureBaseTyped< T > > &wfutureb)
Definition: future.hxx:92
The future has been canceled.
Definition: future_fwd.hpp:78
FutureState wait(int msecs) const
#define QI_API
Definition: api.hpp:34
void continuateThen(const Future< T > &future, const boost::function< R(const Future< T > &)> &func, qi::Promise< R > &promise)
Definition: future.hxx:45
void operator()(const T &in, void *out)
Definition: future.hxx:596
void operator()(void *in, void *out)
Definition: future.hxx:588
boost::function< RF > bind(const AF &fun,...)
void setCanceled(qi::Future< T > &future)
Definition: future.hxx:395
boost::chrono::duration< int64_t, boost::nano > Duration
Convenience typedefs.
Definition: clock.hpp:18
bool isRunning() const
void setup(boost::function< void(qi::Promise< T >)> cancelCallback, FutureCallbackType async=FutureCallbackType_Async)
Definition: future_fwd.hpp:744
FutureBasePrivate * _p
Definition: future.hxx:268
void setValue(qi::Future< T > &future, const ValueType &value)
Definition: future.hxx:346
void setError(const std::string &msg)
Definition: future_fwd.hpp:689
void reportError(const std::string &message)
ValueType & value()
Definition: future_fwd.hpp:714
void set(qi::Future< T > &future)
Definition: future.hxx:363
void callCbNotify(qi::Future< T > &future)
Definition: future.hxx:324
bool isCanceled() const
Definition: future_fwd.hpp:255
bool hasValue(int msecs) const
boost::function< void()> makeCanceler()
Get a functor that will cancel the future.
Definition: future.hxx:230
void trigger()
Definition: future_fwd.hpp:717
Specialize this struct to provide conversion between future values.
Definition: future_fwd.hpp:793
qi::Future< T > makeFutureError(const std::string &error)
Helper function to return a future with the error set.
Definition: future.hxx:548
FutureType< T >::type ValueType
Definition: future.hxx:277
bool isCancelRequested() const
Definition: future_fwd.hpp:703
void post(const boost::function< void()> &callback, uint64_t usDelay)
Similar to async() but without cancelation or notification.
void futureAdapter(Future< FT > f, Promise< PT > p, CONV converter)
Definition: future.hxx:557
void connect(const AF &fun, FutureCallbackType type=FutureCallbackType_Async)
Definition: future_fwd.hpp:376
void post(const boost::function< void()> &callback)
post a callback to be executed as soon as possible
Future< T > future() const
Get a future linked to this promise. Can be called multiple times.
Definition: future_fwd.hpp:708
bool isCancelable() const
Definition: future.hxx:290
boost::shared_ptr< detail::FutureBaseTyped< T > > _p
Definition: future_fwd.hpp:428
#define qiLogError(...)
Log in error mode.
Definition: log.hpp:113
FutureState
Definition: future_fwd.hpp:75
boost::function< void(Promise< T >)> CancelCallback
Definition: future.hxx:276
Operation pending.
Definition: future_fwd.hpp:77
void setOnDestroyed(boost::function< void(ValueType)> f)
Definition: future.hxx:404
bool isCancelable() const
Definition: future_fwd.hpp:308
void cancel()
Definition: future_fwd.hpp:300
EventLoop * getEventLoop()
Return the global eventloop, created on demand on first call.
void connect(qi::Future< T > future, const boost::function< void(qi::Future< T >)> &s, FutureCallbackType type)
Definition: future.hxx:409
The operation is finished with an error.
Definition: future_fwd.hpp:79
bool isCancelRequested() const
void waitForFirstHelper(qi::Promise< qi::Future< T > > &prom, qi::Future< T > &fut, qi::Atomic< int > *count)
Definition: future.hxx:470
bool isFinished() const
detail::FutureType< T >::type ValueType
Definition: future_fwd.hpp:145
boost::function< F > trackWithFallback(boost::function< void()> onFail, const boost::function< F > &f, const ARG0 &arg0)
Wrap given function f with a tracking check on arg0, which must be a weak pointer or a Trackable inst...
Definition: trackable.hxx:212
void setCanceled()
Definition: future_fwd.hpp:696
boost::recursive_mutex & mutex()
void cancel(qi::Future< T > &future)
Definition: future.hxx:295
const std::string & error(int msecs) const
void adaptFuture(const Future< FT > &f, Promise< PT > &p)
Feed a promise from a future of possibly different type.
Definition: future.hxx:621
void futureCancelAdapter(boost::weak_ptr< FutureBaseTyped< FT > > wf)
Definition: future.hxx:578
const std::string & error(int msecs=FutureTimeout_Infinite) const
Definition: future_fwd.hpp:283
const ValueType & value(int msecs=FutureTimeout_Infinite) const
Return the value associated to a Future.
Definition: future_fwd.hpp:200
FutureState state() const
Convenient log macro.
FutureCallbackType
Definition: future_fwd.hpp:83
void setBroken(qi::Future< T > &future)
Definition: future.hxx:386
void setValue(const ValueType &value)
Definition: future_fwd.hpp:682
boost::chrono::time_point< SteadyClock > time_point
Definition: clock.hpp:45
Future< R > andThenR(FutureCallbackType type, const boost::function< R(const typename Future< T >::ValueType &)> &func)
Definition: future.hxx:121
Future< R > thenR(FutureCallbackType type, const boost::function< R(const Future< T > &)> &func)
Definition: future.hxx:105
void setOnCancel(qi::Promise< T > &promise, CancelCallback onCancel)
Definition: future.hxx:310
static R _callfunc(const T &arg, const boost::function< R(const T &)> &func)
Definition: future.hxx:26
const ValueType & value(int msecs) const
Definition: future.hxx:438
void continuateAndThen(const Future< T > &future, const boost::function< R(const typename Future< T >::ValueType &)> &func, qi::Promise< R > &promise)
Definition: future.hxx:64
void operator()(void *in, const T &out)
Definition: future.hxx:604
void adaptFutureUnwrap(Future< AnyReference > &f, Promise< R > &p)
Feed a promise from a generic future which may be unwrapped if it contains itself a future...
Definition: future.hxx:610
bool hasError(int msecs=FutureTimeout_Infinite) const
Definition: future_fwd.hpp:264