libqi-api
2.0.6.8
|
00001 #pragma once 00002 /* 00003 ** Copyright (C) 2012 Aldebaran Robotics 00004 ** See COPYING for the license 00005 */ 00006 00007 #ifndef _QI_FUTURE_HPP_ 00008 #define _QI_FUTURE_HPP_ 00009 00010 #include <qi/api.hpp> 00011 #include <vector> 00012 #include <qi/atomic.hpp> 00013 #include <qi/config.hpp> 00014 #include <qi/trackable.hpp> 00015 00016 #include <boost/shared_ptr.hpp> 00017 #include <boost/make_shared.hpp> 00018 #include <boost/function.hpp> 00019 #include <boost/bind.hpp> 00020 #include <boost/thread/recursive_mutex.hpp> 00021 00022 #ifdef _MSC_VER 00023 # pragma warning( push ) 00024 # pragma warning( disable: 4251 ) 00025 # pragma warning( disable: 4275 ) //std::runtime_error: no dll interface 00026 #endif 00027 00028 namespace qi { 00029 00030 template<typename T> 00031 struct FutureType 00032 { 00033 typedef T type; 00034 typedef T typecast; 00035 }; 00036 00037 struct FutureHasNoValue {}; 00038 // Hold a void* for Future<void> 00039 template<> 00040 struct FutureType<void> 00041 { 00042 typedef void* type; 00043 typedef FutureHasNoValue typecast; 00044 }; 00045 00046 template <typename T> class FutureInterface; 00047 template <typename T> class Future; 00048 template <typename T> class FutureSync; 00049 template <typename T> class Promise; 00050 00051 namespace detail { 00052 template <typename T> class FutureBaseTyped; 00053 00054 template<typename FT> 00055 void futureCancelAdapter( 00056 boost::weak_ptr<detail::FutureBaseTyped<FT> > wf); 00057 } 00058 00061 enum FutureState { 00062 FutureState_None, 00063 FutureState_Running, 00064 FutureState_Canceled, 00065 FutureState_FinishedWithError, 00066 FutureState_FinishedWithValue, 00067 }; 00068 00069 enum FutureCallbackType { 00070 FutureCallbackType_Sync = 0, 00071 FutureCallbackType_Async = 1 00072 }; 00073 00074 enum FutureTimeout { 00075 FutureTimeout_Infinite = ((int) 0x7fffffff), 00076 FutureTimeout_None = 0, 00077 }; 00078 00081 class QI_API FutureException : public std::runtime_error { 00082 public: 00083 enum ExceptionState { 00084 //No result ready 00085 ExceptionState_FutureTimeout, 00086 //The future has been canceled 00087 ExceptionState_FutureCanceled, 00088 //The future is not cancelable 00089 ExceptionState_FutureNotCancelable, 00090 //asked for error, but there is no error 00091 ExceptionState_FutureHasNoError, 00092 //real future error 00093 ExceptionState_FutureUserError, 00094 //when the promise is already set. 00095 ExceptionState_PromiseAlreadySet, 00096 }; 00097 00098 explicit FutureException(const ExceptionState &es, const std::string &str = std::string()) 00099 : std::runtime_error(stateToString(es) + str) 00100 , _state(es) 00101 {} 00102 00103 inline ExceptionState state() const { return _state; } 00104 00105 std::string stateToString(const ExceptionState &es); 00106 00107 virtual ~FutureException() throw() 00108 {} 00109 00110 private: 00111 ExceptionState _state; 00112 }; 00113 00117 class QI_API FutureUserException : public FutureException { 00118 public: 00119 00120 explicit FutureUserException(const std::string &str = std::string()) 00121 : FutureException(ExceptionState_FutureUserError, str) 00122 {} 00123 00124 virtual ~FutureUserException() throw() 00125 {} 00126 }; 00127 00128 template <typename T> 00129 class Future { 00130 public: 00131 typedef typename FutureType<T>::type ValueType; 00132 typedef typename FutureType<T>::typecast ValueTypeCast; 00133 00134 public: 00135 Future() 00136 : _p(boost::make_shared<detail::FutureBaseTyped<T> >()) 00137 { 00138 } 00139 00140 Future(const Future<T>& b) 00141 : _p(b._p) 00142 {} 00143 00144 bool operator==(const Future<T> &other) 00145 { 00146 return _p.get() == other._p.get(); 00147 } 00148 00149 inline Future<T>& operator=(const Future<T>& b) 00150 { 00151 _p = b._p; 00152 return *this; 00153 } 00154 00155 bool operator < (const Future<T>& b) const 00156 { 00157 return _p.get() < b._p.get(); 00158 } 00159 explicit Future<T>(const ValueType& v, FutureCallbackType async = FutureCallbackType_Async) 00160 { 00161 Promise<T> promise(async); 00162 promise.setValue(v); 00163 *this = promise.future(); 00164 } 00165 00178 inline const ValueType &value(int msecs = FutureTimeout_Infinite) const { return _p->value(msecs); } 00179 00182 inline operator const ValueTypeCast&() const { return _p->value(FutureTimeout_Infinite); } 00183 00188 inline FutureState wait(int msecs = FutureTimeout_Infinite) const { return _p->wait(msecs); } 00189 00195 inline bool isFinished() const { return _p->isFinished(); } 00196 00202 inline bool isRunning() const { return _p->isRunning(); } 00203 00209 inline bool isCanceled() const { return _p->isCanceled(); } 00210 00218 inline bool hasError(int msecs = FutureTimeout_Infinite) const { return _p->hasError(msecs); } 00227 inline bool hasValue(int msecs = FutureTimeout_Infinite) const { return _p->hasValue(msecs); } 00228 00236 inline const std::string &error(int msecs = FutureTimeout_Infinite) const { return _p->error(msecs); } 00237 00238 00239 inline FutureSync<T> sync() 00240 { 00241 return FutureSync<T>(*this); 00242 }; 00243 00250 void cancel() 00251 { 00252 _p->cancel(*this); 00253 } 00254 00257 bool isCancelable() const 00258 { 00259 return _p->isCancelable(); 00260 } 00261 public: //Signals 00262 typedef boost::function<void (Future<T>) > Connection; 00267 inline void connect(const Connection& s) { _p->connect(*this, s);} 00268 00269 #ifdef DOXYGEN 00270 00276 template<typename FUNCTYPE, typename ARG0> 00277 void connect(FUNCTYPE fun, ARG0 tracked, ...); 00278 #else 00279 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \ 00280 template<typename AF, typename ARG0 comma ATYPEDECL> \ 00281 inline void connect(const AF& fun, const ARG0& arg0 comma ADECL) \ 00282 { \ 00283 connect(::qi::bind<void(Future<T>)>(fun, arg0 comma AUSE)); \ 00284 } 00285 QI_GEN(genCall) 00286 #undef genCall 00287 #endif 00288 00289 // Our companion library libqitype requires a connect with same signature for all instantiations 00290 inline void _connect(const boost::function<void()>& s) { connect(boost::bind(s));} 00291 00292 boost::shared_ptr<detail::FutureBaseTyped<T> > impl() { return _p;} 00293 Future(boost::shared_ptr<detail::FutureBaseTyped<T> > p) : 00294 _p(p) 00295 { 00296 assert(_p); 00297 } 00298 protected: 00299 // C4251 needs to have dll-interface to be used by clients of class 'qi::Future<T>' 00300 boost::shared_ptr< detail::FutureBaseTyped<T> > _p; 00301 friend class Promise<T>; 00302 friend class FutureSync<T>; 00303 00304 template<typename FT, typename PT> 00305 friend void adaptFuture(const Future<FT>& f, Promise<PT>& p); 00306 template<typename FT, typename PT, typename CONV> 00307 friend void adaptFuture(const Future<FT>& f, Promise<PT>& p, 00308 CONV converter); 00309 template<typename FT> 00310 friend void detail::futureCancelAdapter( 00311 boost::weak_ptr<detail::FutureBaseTyped<FT> > wf); 00312 }; 00313 00314 00315 00319 template<typename T> 00320 class FutureSync 00321 { 00322 public: 00323 typedef typename Future<T>::ValueType ValueType; 00324 typedef typename Future<T>::ValueTypeCast ValueTypeCast; 00325 typedef typename Future<T>::Connection Connection; 00326 // This future cannot be set, so sync starts at false 00327 FutureSync() : _sync(false) {} 00328 00329 FutureSync(const Future<T>& b) 00330 : _sync(true) 00331 { 00332 _future = b; 00333 } 00334 00335 FutureSync(const FutureSync<T>& b) 00336 : _sync(true) 00337 { 00338 _future = b._future; 00339 b._sync = false; 00340 } 00341 00342 explicit FutureSync<T>(const ValueType& v) 00343 : _sync(false) 00344 { 00345 Promise<T> promise; 00346 promise.setValue(v); 00347 _future = promise.future(); 00348 } 00349 00350 inline FutureSync<T>& operator=(const FutureSync<T>& b) 00351 { 00352 _future = b; 00353 _sync = true; 00354 b._sync = false; 00355 return *this; 00356 } 00357 00358 inline FutureSync<T>& operator=(const Future<T>& b) 00359 { 00360 _future = b; 00361 _sync = true; 00362 return *this; 00363 } 00364 00365 ~FutureSync() 00366 { 00367 if (_sync) 00368 _future.value(); 00369 } 00370 00371 operator Future<T>() 00372 { 00373 return async(); 00374 } 00375 00376 bool operator < (const FutureSync<T>& b) const 00377 { 00378 return _future._p.get() < b._future._p.get(); 00379 } 00380 00381 const ValueType &value(int msecs = FutureTimeout_Infinite) const { _sync = false; return _future.value(msecs); } 00382 operator const typename Future<T>::ValueTypeCast&() const { _sync = false; return _future.value(); } 00383 FutureState wait(int msecs = FutureTimeout_Infinite) const { _sync = false; return _future.wait(msecs); } 00384 bool isRunning() const { _sync = false; return _future.isRunning(); } 00385 bool isFinished() const { _sync = false; return _future.isFinished(); } 00386 bool isCanceled() const { _sync = false; return _future.isCanceled(); } 00387 bool hasError(int msecs = FutureTimeout_Infinite) const { _sync = false; return _future.hasError(msecs); } 00388 bool hasValue(int msecs = FutureTimeout_Infinite) const { _sync = false; return _future.hasValue(msecs); } 00389 const std::string &error(int msecs = FutureTimeout_Infinite) const { _sync = false; return _future.error(msecs); } 00390 void cancel() { _sync = false; _future.cancel(); } 00391 bool isCancelable() const { _sync = false; return _future.isCancelable(); } 00392 void connect(const Connection& s) { _sync = false; _future.connect(s);} 00393 void _connect(const boost::function<void()>& s) { _sync = false; _future._connect(s);} 00394 00395 #ifdef DOXYGEN 00396 00402 template<typename FUNCTYPE, typename ARG0> 00403 void connect(FUNCTYPE fun, ARG0 tracked, ...); 00404 #else 00405 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \ 00406 template<typename AF, typename ARG0 comma ATYPEDECL> \ 00407 inline void connect(const AF& fun, const ARG0& arg0 comma ADECL) \ 00408 { \ 00409 _sync = false; \ 00410 connect(::qi::bind<void(FutureSync<T>)>(fun, arg0 comma AUSE)); \ 00411 } 00412 QI_GEN(genCall) 00413 #undef genCall 00414 #endif 00415 00416 Future<T> async() 00417 { 00418 _sync = false; 00419 return _future; 00420 } 00421 00422 protected: 00423 mutable bool _sync; 00424 Future<T> _future; 00425 friend class Future<T>; 00426 }; 00427 00428 00431 template <typename T> 00432 class Promise { 00433 public: 00434 typedef typename FutureType<T>::type ValueType; 00435 00441 explicit Promise(FutureCallbackType async = FutureCallbackType_Async) { 00442 _f._p->reportStart(); 00443 _f._p->_async = async; 00444 } 00445 00451 explicit Promise(boost::function<void (qi::Promise<T>)> cancelCallback, FutureCallbackType async = FutureCallbackType_Async) 00452 { 00453 setup(cancelCallback, async); 00454 } 00455 00459 void setValue(const ValueType &value) { 00460 _f._p->setValue(_f, value); 00461 } 00462 00466 void setError(const std::string &msg) { 00467 _f._p->setError(_f, msg); 00468 } 00469 00473 void setCanceled() { 00474 _f._p->setCanceled(_f); 00475 } 00476 00477 /* reset the promise and the future */ 00478 void reset() { 00479 _f._p->reset(); 00480 } 00481 00483 Future<T> future() const { return _f; } 00484 00488 ValueType& value() { return _f._p->_value;} 00491 void trigger() { _f._p->set(_f);} 00492 protected: 00493 void setup(boost::function<void (qi::Promise<T>)> cancelCallback, FutureCallbackType async = FutureCallbackType_Async) 00494 { 00495 this->_f._p->reportStart(); 00496 this->_f._p->setOnCancel(cancelCallback); 00497 this->_f._p->_async = async; 00498 } 00499 explicit Promise(Future<T>& f) : _f(f) {} 00500 template<typename> friend class ::qi::detail::FutureBaseTyped; 00501 Future<T> _f; 00502 00503 template<typename FT, typename PT> 00504 friend void adaptFuture(const Future<FT>& f, Promise<PT>& p); 00505 template<typename FT, typename PT, typename CONV> 00506 friend void adaptFuture(const Future<FT>& f, Promise<PT>& p, 00507 CONV converter); 00508 }; 00509 00510 template<typename T> 00511 class FutureBarrier { 00512 public: 00514 FutureBarrier(FutureCallbackType async = FutureCallbackType_Async) 00515 : _closed(false) 00516 , _count(0) 00517 , _futures() 00518 , _promise(async) 00519 {} 00520 00522 bool addFuture(qi::Future<T> fut) { 00523 // Can't add future from closed qi::FutureBarrier. 00524 if (this->_closed) 00525 return false; 00526 00527 ++(this->_count); 00528 fut.connect(boost::bind<void>(&FutureBarrier::onFutureFinish, this)); 00529 this->_futures.push_back(fut); 00530 return true; 00531 } 00532 00534 Future< std::vector< Future<T> > > future() { 00535 this->close(); 00536 return this->_promise.future(); 00537 } 00538 00539 protected: 00540 bool _closed; 00541 Atomic<int> _count; 00542 std::vector< Future<T> > _futures; 00543 Promise< std::vector< Future<T> > > _promise; 00544 00545 private: 00546 void onFutureFinish() { 00547 if (--(this->_count) == 0 && this->_closed) { 00548 this->_promise.setValue(this->_futures); 00549 } 00550 } 00551 00552 void close() { 00553 this->_closed = true; 00554 if (*(this->_count) == 0) { 00555 this->_promise.setValue(this->_futures); 00556 } 00557 } 00558 }; 00559 00560 template <typename T> 00561 qi::Future<T> makeFutureError(const std::string &value, FutureCallbackType async = FutureCallbackType_Async); 00562 00564 template <typename T> 00565 void waitForAll(std::vector< Future<T> >& vect); 00566 00568 template <typename T> 00569 qi::FutureSync< qi::Future<T> > waitForFirst(std::vector< Future<T> >& vect); 00570 00572 template<typename FT, typename PT> 00573 struct FutureValueConverter 00574 { 00575 void operator()(const FT& vIn, PT& vOut) { vOut = vIn;} 00576 }; 00577 00583 template<typename FT, typename PT> 00584 void adaptFuture(const Future<FT>& f, Promise<PT>& p); 00585 00587 template<typename FT, typename PT, typename CONV> 00588 void adaptFuture(const Future<FT>& f, Promise<PT>& p, CONV converter); 00589 } 00590 00591 #ifdef _MSC_VER 00592 # pragma warning( pop ) 00593 #endif 00594 00595 #include <qi/details/future.hxx> 00596 00597 #endif // _QI_FUTURE_HPP_