7 #ifndef _QI_FUTURE_HPP_
8 # define _QI_FUTURE_HPP_
11 # include <type_traits>
14 # include <ka/functional.hpp>
18 # include <qi/config.hpp>
26 # include <boost/shared_ptr.hpp>
27 # include <boost/make_shared.hpp>
28 # include <boost/function.hpp>
29 # include <boost/bind.hpp>
30 # include <boost/thread/recursive_mutex.hpp>
31 # include <boost/exception/diagnostic_information.hpp>
34 # pragma warning( push )
35 # pragma warning( disable: 4251 )
36 # pragma warning( disable: 4275 ) //std::runtime_error: no dll interface
69 template <
typename T>
class Future;
100 throw std::runtime_error(
"Unknown FutureState value: " +
os::to_string(x));
150 : std::runtime_error(stateToString(es) + str)
156 std::string stateToString(
const ExceptionState &es);
162 ExceptionState _state;
183 template <
typename T>
184 class Future :
public detail::AddUnwrap<T> {
185 static_assert(!std::is_const<T>::value,
"can't create a future of const");
193 :
_p(boost::make_shared<detail::FutureBaseTyped<T> >())
203 return _p.get() == other._p.get();
212 bool operator < (const Future<T>& b)
const
214 return _p.get() < b._p.get();
251 return _p->value(msecs);
297 {
return _p->wait(msecs); }
304 {
return _p->wait(duration); }
307 {
return this->
wait(duration); }
314 {
return _p->wait(timepoint); }
317 {
return this->
wait(timepoint); }
324 {
return _p->isFinished(); }
331 {
return _p->isRunning(); }
340 {
return _p->isCanceled(); }
349 {
return _p->hasError(msecs); }
359 {
return _p->hasValue(msecs); }
368 {
return _p->error(msecs); }
412 template <
typename R,
typename AF>
421 template <
typename R,
typename AF>
431 template <
typename R,
typename AF,
typename Arg0,
typename... Args>
438 template <
typename R,
typename AF,
typename Arg0,
typename... Args>
452 template <
typename F>
456 return thenRImpl<typename std::result_of<F(Future<T>)>::type, F>(type, std::forward<F>(func));
462 template <
typename AF>
480 template <
typename R,
typename AF>
489 template <
typename R,
typename AF>
505 template <
typename F>
509 return this->andThenRImpl<typename std::decay<typename std::result_of<F(ValueType)>::type>::type, F>(type, std::forward<F>(func));
515 template <
typename AF>
544 template<
typename AF>
548 _p->connect(*
this, fun, type);
557 template<
typename FUNCTYPE,
typename ARG0>
558 void connect(FUNCTYPE fun, ARG0 tracked, ...,
561 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
562 template <typename AF, typename ARG0 comma ATYPEDECL> \
563 QI_API_DEPRECATED_MSG(please use overload taking only a function and not argument instead)\
564 void connect(const AF& fun, const ARG0& arg0 comma ADECL, \
565 FutureCallbackType type = FutureCallbackType_Auto);
573 const boost::function<
void(
const Future<T>&)>& cb);
575 const boost::function<
void(
const Future<T>&)>& cb);
578 inline void _connect(
const boost::function<
void()>& s)
588 boost::shared_ptr<detail::FutureBaseTyped<T> >
impl() {
return _p;}
598 boost::shared_ptr< detail::FutureBaseTyped<T> >
_p;
604 template<
typename FT,
typename PT>
606 template<
typename FT,
typename PT,
typename CONV>
612 template<
typename FT>
620 template <
typename R,
typename AF>
624 template <
typename R,
typename AF>
628 void setOnDestroyed(boost::function<
void(
ValueType)> cb)
630 _p->setOnDestroyed(cb);
697 static const auto logKnownError = [](
const char* message)
700 <<
"Error in future on destruction: '" << message
701 <<
"' - continuing stack unwinding...";
708 catch(
const std::exception& err)
710 logKnownError(err.what());
713 catch(
const boost::exception& err)
715 logKnownError(boost::diagnostic_information(err).c_str());
721 <<
"Unknown error in future on destruction - continuing stack unwinding...";
732 bool operator < (const FutureSync<T>& b)
const
734 return _future._p.get() < b._future._p.get();
773 template<
typename FUNCTYPE,
typename ARG0>
774 void connect(FUNCTYPE fun, ARG0 tracked, ...);
776 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
777 template<typename AF, typename ARG0 comma ATYPEDECL> \
778 QI_API_DEPRECATED_MSG(please use overload taking only a function and not argument instead)\
779 void connect(const AF& fun, const ARG0& arg0 comma ADECL);
800 template <
typename T>
811 _f._p->reportStart();
813 ++
_f._p->_promiseCount;
821 template <
typename FUNC,
822 typename std::enable_if<!std::is_same<
823 typename std::decay<FUNC>::type,
824 typename std::decay<qi::Promise<T> >::type
830 setup(std::forward<FUNC>(cancelCallback),
async);
831 ++
_f._p->_promiseCount;
838 ++
_f._p->_promiseCount;
844 ++
_f._p->_promiseCount;
856 _f._p->setValue(
_f, value);
863 _f._p->setError(
_f, msg);
870 _f._p->setCanceled(
_f);
877 return _f._p->isCancelRequested();
900 this->
_f._p->setOnCancel(*
this, cancelCallback);
905 if (
_f._p == rhs.
_f._p)
910 ++
_f._p->_promiseCount;
917 this->
_f._p->reportStart();
918 this->
_f._p->setOnCancel(*
this, cancelCallback);
922 ++
_f._p->_promiseCount;
924 template<
typename>
friend class ::qi::detail::FutureBaseTyped;
929 template<
typename FT,
typename PT>
931 template<
typename FT,
typename PT,
typename CONV>
944 if (--
_f._p->_promiseCount == 0 &&
_f._p.use_count() > 1 &&
_f.isRunning())
945 _f._p->setBroken(
_f);
951 class FutureBasePrivate;
961 bool isRunning()
const;
962 bool isFinished()
const;
963 bool isCanceled()
const;
964 bool isCancelRequested()
const;
965 bool hasError(
int msecs)
const;
966 bool hasValue(
int msecs)
const;
967 const std::string &error(
int msecs)
const;
972 void reportError(
const std::string &message);
973 void requestCancel();
974 void reportCanceled();
975 boost::recursive_mutex& mutex();
979 FutureBasePrivate *
_p;
984 template <
typename T>
1014 using CallbackType = boost::function<void(qi::Future<T>)>;
1017 CallbackType callback;
1021 : callback(callback)
1022 , callType(callType)
1025 using Callbacks = std::vector<Callback>;
1026 Callbacks _onResult;
1029 boost::function<void (ValueType)> _onDestroyed;
1030 std::atomic<FutureCallbackType> _async;
1033 template <
typename F>
1037 Callbacks takeOutResultCallbacks();
1040 void clearCancelCallback();
1042 static void executeCallbacks(
bool defaultAsync,
const Callbacks& callbacks,
qi::Future<T>& future);
1050 template <
typename T>
1056 template <
typename T>
1063 template<
typename FT,
typename PT>
1072 template<
typename R>
1082 template<
typename FT,
typename PT>
1086 template<
typename FT,
typename PT,
typename CONV>
1087 void adaptFuture(
const Future<FT>& f, Promise<PT>& p, CONV converter,
1091 template <
typename T>
1094 return future.makeCanceler();
1099 template <
typename T>
1131 template<typename T>
1156 KA_GENERATE_FRIEND_REGULAR_OPS_0(
SrcFuture)
1161 template<
typename T>
1199 template<
typename... T>
1223 template<
typename Proc>
1225 -> decltype(ka::semilift(std::forward<Proc>(p),
UnitFuture{}))
1227 return ka::semilift(std::forward<Proc>(p),
UnitFuture{});
1238 template <
typename T>
1239 template <
typename R,
typename AF,
typename Arg0,
typename... Args>
1242 return thenRImpl<R>(
1244 qi::bind(std::forward<AF>(func), std::forward<Arg0>(arg0), std::forward<Args>(args)...));
1247 template <
typename T>
1248 template <
typename R,
typename AF,
typename Arg0,
typename... Args>
1251 return thenRImpl<R>(
1253 qi::bind(std::forward<AF>(func), arg0, std::forward<Args>(args)...));
1256 #ifndef DOXYGEN // skip those complicated macros in documentation
1257 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
1258 template <typename T> \
1259 template <typename AF, typename ARG0 comma ATYPEDECL> \
1260 void Future<T>::connect( \
1261 const AF& fun, const ARG0& arg0 comma ADECL, FutureCallbackType type) \
1263 this->then(type, qi::bind(fun, arg0 comma AUSE)); \
1268 #define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma) \
1269 template <typename T> \
1270 template <typename AF, typename ARG0 comma ATYPEDECL> \
1271 void FutureSync<T>::connect(const AF& fun, const ARG0& arg0 comma ADECL) \
1274 connect(::qi::bind<void(FutureSync<T>)>(fun, arg0 comma AUSE)); \
1282 # pragma warning( pop )
1285 #endif // _QI_FUTURE_HPP_
auto then(AF &&func) -> Future< typename std::result_of< AF(Future< T >)>::type >
Same as then(), but with type defaulted to FutureCallbackType_Auto.
asked for error, but there is no error
void setError(qi::Future< T > &future, const std::string &message)
Future< AnyValue > toAnyValueFuture(Future< T > future)
when the promise is already set.
void operator()(const FT &vIn, PT &vOut)
ValueType operator*() const
Return the value associated to a Future.
void setup(boost::function< void(qi::Promise< T > &)> cancelCallback, FutureCallbackType async=FutureCallbackType_Auto)
void connect(const AF &fun, FutureCallbackType type=FutureCallbackType_Auto)
The future has been canceled.
friend void adaptFuture(const Future< FT > &f, Promise< PT > &p, AdaptFutureOption option)
Feed a promise from a future of possibly different type.
void PromiseNoop(qi::Promise< T > &)
friend UnitFuture retract(SrcFuture)
MilliSeconds::rep operator()(Infinity) const
void setCanceled(qi::Future< T > &future)
void connect(const Connection &s)
typename Future< T >::Connection Connection
FutureState waitFor(qi::Duration duration) const
The future has been canceled.
void _connect(const boost::function< void()> &s)
void setValue(qi::Future< T > &future, const ValueType &value)
friend 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...
TimePoint< SteadyClock > time_point
void setError(const std::string &msg)
FutureState wait(qi::Duration duration) const
std::ostream & operator<<(std::ostream &o, FutureState x)
void set(qi::Future< T > &future)
friend 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...
#define QI_ASSERT(expr__)
ExceptionState state() const
const ValueType & value(int msecs=FutureTimeout_Infinite) const
FutureUserException(const std::string &str=std::string())
FutureState wait(qi::SteadyClock::time_point timepoint) const
dll import/export and compiler message
auto futurize(T &&...t) -> decltype(UnitFuture
FutureSync(const Future< T > &b)
boost::function< void()> makeCanceler()
Get a functor that will cancel the future.
boost::shared_ptr< const T > valueSharedPtr(Either< MilliSeconds, Infinity > timeout=Infinity{}) const
Return a shared pointer to the value associated to a Future.
typename Future< T >::ValueType ValueType
Specialize this struct to provide conversion between future values.
qi::Future< T > makeFutureError(const std::string &error)
Helper function to return a future with the error set.
#define qiLogWarning(...)
Log in warning mode.
void _connect(const boost::function< void()> &s)
const std::string & error(int msecs=FutureTimeout_Infinite) const
void connect(qi::Future< T > future, const boost::function< void(qi::Future< T >)> &callback, FutureCallbackType type)
auto then(FutureCallbackType type, F &&func) -> Future< typename std::result_of< F(Future< T >)>::type >
Execute a callback when the future is finished.
bool isCancelRequested() const
Future< void > operator()() const
#define QI_NOEXCEPT(cond)
Specify that a function may throw or not. Do nothing if noexcept is not available.
const ValueType & value(Either< MilliSeconds, Infinity > timeout) const
typename detail::FutureType< void >::type ValueType
Future< T > future() const
Get a future linked to this promise. Can be called multiple times.
typename Future< T >::ValueTypeCast ValueTypeCast
Future< R > andThenR(FutureCallbackType type, AF &&func)
Same as thenR(), but the callback is called only if this future finishes with a value.
boost::shared_ptr< detail::FutureBaseTyped< T > > _p
virtual ~FutureUserException()
boost::function< void(Future< void >)> Connection
the future is not associated to a promise
const ValueType & value(int msecs) const
DurationType< int64_t, boost::milli > MilliSeconds
boost::shared_ptr< const T > valueSharedPtr(int msecs=FutureTimeout_Infinite) const
FutureState wait(qi::SteadyClock::time_point timepoint) const
typename FutureType< T >::type ValueType
#define genCall(n, ATYPEDECL, ATYPES, ADECL, AUSE, comma)
friend class ServiceBoundObject
Future is not tied to a promise.
boost::function< void()> makeCanceler(Future< T > &future)
#define QI_API_DEPRECATED_MSG(msg__)
Compiler flags to mark a function as deprecated. It will generate a compiler warning.
auto operator()(const Future< T > &x) const QI_NOEXCEPT_EXPR(*x) -> decltype(*x)
FutureState waitUntil(qi::SteadyClock::time_point timepoint) const
FutureException(const ExceptionState &es, const std::string &str=std::string())
void setOnDestroyed(boost::function< void(ValueType)> f)
auto async(F &&callback) -> decltype(asyncDelay(std::forward< F >(callback), qi::Duration(0)))
~FutureSync() QI_NOEXCEPT(false)
Promise(FutureCallbackType async=FutureCallbackType_Auto)
bool operator==(const Future< T > &other) const
auto visit(Proc &&proc, T &&variant) -> decltype(boost::apply_visitor(ka::fwd< Proc >(proc), ka::fwd< T >(variant)))
bool isCancelable() const
typename detail::FutureType< void >::type ValueType
boost::variant< A, B > Either
Convenient alias to a variant of two types.
Future(const Future< T > &b)
FutureState wait(qi::Duration duration) const
bool isCancelable() const
The operation is finished with an error.
auto andThen(AF &&func) -> Future< typename std::decay< typename std::result_of< AF(ValueType)>::type >::type >
Same as andThen(), but with type defaulted to FutureCallbackType_Auto.
Future< R > thenR(FutureCallbackType type, AF &&func)
Execute a callback when the future is finished.
FutureSync< T > & operator=(const Future< T > &b)
auto andThen(FutureCallbackType type, F &&func) -> Future< typename std::decay< typename std::result_of< F(ValueType)>::type >::type >
Same as then(), but the callback is called only if this future finishes with a value.
FutureState waitFor(qi::Duration duration) const
boost::function< void(Promise< T > &)> CancelCallback
FutureState wait(int msecs=FutureTimeout_Infinite) const
virtual ~FutureException()
FutureState wait(int msecs=FutureTimeout_Infinite) const
void cancel(qi::Future< T > &future)
bool hasValue(int msecs=FutureTimeout_Infinite) const
void setOnCancel(boost::function< void(qi::Promise< T > &)> cancelCallback)
friend void adaptFuture(const Future< FT > &f, Promise< PT > &p, AdaptFutureOption option)
Feed a promise from a future of possibly different type.
void futureCancelAdapter(boost::weak_ptr< FutureBaseTyped< FT > > wf)
Promise(FUNC &&cancelCallback, FutureCallbackType async=FutureCallbackType_Auto)
const std::string & error(int msecs=FutureTimeout_Infinite) const
Promise< T > & operator=(const Promise< T > &rhs)
#define QI_NOEXCEPT_EXPR(expr)
Specify that a function may throw if the given expression may throw. Do nothing if noexcept is not av...
bool hasValue(int msecs=FutureTimeout_Infinite) const
const ValueType & value(int msecs=FutureTimeout_Infinite) const
Return the value associated to a Future.
FutureSync(const FutureSync< T > &b)
FutureUniqueId uniqueId() const
Promise(const qi::Promise< T > &rhs)
FutureUniqueId uniqueId() const
std::string to_string(N n)
(Arithmetic or Enum) N
void setBroken(qi::Future< T > &future)
void setValue(const ValueType &value)
FutureSync< T > & operator=(const FutureSync< T > &b)
Promise(boost::function< void(qi::Promise< T >)> cancelCallback, FutureCallbackType async=FutureCallbackType_Auto)
Future< T > & operator=(const Future< T > &b)
void setOnCancel(const qi::Promise< T > &promise, CancelCallback onCancel)
ValueType valueCopy(Either< MilliSeconds, Infinity > timeout=Infinity{}) const
Return by copy the value associated to a Future.
bool hasError(int msecs=FutureTimeout_Infinite) const
void adaptFuture(const Future< FT > &f, Promise< PT > &p, AdaptFutureOption option)
Feed a promise from a future of possibly different type.
boost::shared_ptr< detail::FutureBaseTyped< T > > impl()
An accessor to the shared state. TODO: remove it, it should not exist.
FutureState waitUntil(qi::SteadyClock::time_point timepoint) const
void connectWithStrand(qi::Strand *strand, const boost::function< void(const Future< T > &)> &cb)
The operation is finished with a value.
typename detail::FutureType< void >::typecast ValueTypeCast
SrcFuture retract(UnitFuture)
std::enable_if< std::is_function< RF >::value, boost::function< RF > >::type bind(AF &&fun, Arg0 &&arg0, Args &&...args)
Future(boost::shared_ptr< detail::FutureBaseTyped< T > > p)
The constructor from the shared state.
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...
ValueType valueCopy(int msecs=FutureTimeout_Infinite) const
auto futurizeOutput(Proc &&p) -> decltype(ka::semilift(std::forward< Proc >(p), UnitFuture
bool hasError(int msecs=FutureTimeout_Infinite) const
MilliSeconds::rep operator()(MilliSeconds x) const