32 #include <type_traits> 35 #include <boost/optional.hpp> 36 #include <QFutureInterface> 37 #include <QFutureWatcher> 38 #include <QtConcurrentRun> 47 template<
typename R,
typename F,
typename... Args>
48 EnableIf_t<!std::is_same<R, void>::value>
53 const auto result =
Invoke (std::forward<F> (f), std::forward<Args> (args)...);
54 iface.reportFinished (&result);
58 iface.reportException (e);
59 iface.reportFinished ();
61 catch (
const std::exception& e)
64 iface.reportFinished ();
68 template<
typename F,
typename... Args>
73 Invoke (std::forward<F> (f), std::forward<Args> (args)...);
77 iface.reportException (e);
79 catch (
const std::exception& e)
84 iface.reportFinished ();
109 constexpr
static bool Result_ =
false;
115 constexpr
static bool Result_ =
true;
118 template<
typename RetType,
typename ResultHandler>
121 void operator() (
const ResultHandler& rh, QFutureWatcher<RetType> *watcher)
const 123 rh (watcher->result ());
127 template<
typename ResultHandler>
130 void operator() (
const ResultHandler& rh, QFutureWatcher<void>*)
const 136 template<
typename ResultHandler,
typename RetType,
typename = ResultOf_t<ResultHandler (RetType)>>
142 template<
typename,
typename>
148 template<
typename ResultHandler,
typename = ResultOf_t<ResultHandler ()>>
160 template<
typename ResultHandler,
typename RetType>
163 return std::is_same<void, RetType>::value ?
164 IsCompatibleImplVoid<ResultHandler> (0) :
165 IsCompatibleImpl<ResultHandler, RetType> (0);
192 template<
typename Executor,
typename ResultHandler,
typename... Args>
193 void ExecuteFuture (Executor f, ResultHandler rh, QObject *parent, Args... args)
196 "The passed functor should return a QFuture.");
202 static_assert (detail::IsCompatible<ResultHandler, RetType_t> (),
203 "Executor's watcher type and result handler argument type are not compatible.");
205 const auto watcher =
new QFutureWatcher<RetType_t> { parent };
211 watcher->deleteLater ();
215 SIGNAL (finished ()),
219 watcher->setFuture (f (args...));
236 template<
typename Future>
246 QFutureWatcher<RetType_t> BaseWatcher_;
247 QObject *LastWatcher_ = &BaseWatcher_;
258 , BaseWatcher_ {
this }
269 BaseWatcher_.setFuture (Future_);
292 template<
typename RetT,
typename ArgT>
295 const auto last =
dynamic_cast<QFutureWatcher<ArgT>*
> (LastWatcher_);
299 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
302 const auto watcher =
new QFutureWatcher<RetT> {
this };
303 LastWatcher_ = watcher;
307 [
this, last, watcher, action]
309 if (static_cast<QObject*> (last) != &BaseWatcher_)
310 last->deleteLater ();
311 watcher->setFuture (action (last->result ()));
314 SIGNAL (finished ()),
339 template<
typename ArgT>
340 void Then (
const std::function<
void (ArgT)>& action)
342 const auto last =
dynamic_cast<QFutureWatcher<ArgT>*
> (LastWatcher_);
346 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
353 action (last->result ());
357 SIGNAL (finished ()),
362 void Then (
const std::function<
void ()>& action)
364 const auto last =
dynamic_cast<QFutureWatcher<void>*
> (LastWatcher_);
368 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
379 SIGNAL (finished ()),
388 struct EmptyDestructionTag;
393 template<typename Ret, typename DestrType, typename = EnableIf_t<IsEmptyDestr_t<DestrType>::value>>
398 template<typename Ret, typename DestrType, typename = EnableIf_t<!IsEmptyDestr_t<DestrType>::value>>
401 const auto res = handler ();
402 iface.reportFinished (&res);
421 template<
typename Ret,
typename Future,
typename DestructionTag>
424 template<
typename,
typename,
typename>
427 std::shared_ptr<void> ExecuteGuard_;
430 boost::optional<QFuture<Ret>> ThisFuture_;
432 std::function<DestructionTag ()> DestrHandler_;
435 const std::function<DestructionTag ()>& destrHandler)
436 : ExecuteGuard_ { guard }
438 , DestrHandler_ { destrHandler }
450 : ExecuteGuard_ {
nullptr, [sequencer] (
void*) { sequencer->
Start (); } }
487 throw std::runtime_error {
"SequenceProxy::Then(): cannot chain more after being converted to a QFuture" };
489 Seq_->template Then<UnwrapFutureType_t<decltype (f (std::declval<Ret> ()))>, Ret> (f);
490 return { ExecuteGuard_, Seq_, DestrHandler_ };
509 throw std::runtime_error {
"SequenceProxy::Then(): cannot chain more after being converted to a QFuture" };
511 Seq_->template Then<Ret> (f);
518 throw std::runtime_error {
"SequenceProxy::Then(): cannot chain more after being converted to a QFuture" };
520 Seq_->Then (std::function<
void ()> { f });
524 auto operator>> (F&& f) -> decltype (this->Then (std::forward<F> (f)))
526 return Then (std::forward<F> (f));
532 static_assert (std::is_same<DestructionTag, EmptyDestructionTag>::value,
533 "Destruction handling function has been already set.");
535 return { ExecuteGuard_, Seq_, std::forward<F> (f) };
540 constexpr
bool isEmptyDestr = std::is_same<DestructionTag, EmptyDestructionTag>::value;
541 static_assert (std::is_same<DestructionTag, Ret>::value || isEmptyDestr,
542 "Destruction handler's return type doesn't match expected future type.");
547 QFutureInterface<Ret> iface;
548 iface.reportStarted ();
554 const auto destrHandler = DestrHandler_;
557 [destrHandler, iface] ()
mutable 559 if (iface.isFinished ())
562 InvokeDestructionHandler<Ret, DestructionTag> (destrHandler, iface, 0);
565 SIGNAL (destroyed ()),
570 Then ([deleteGuard, iface] (
const Ret& ret)
mutable 572 iface.reportFinished (&ret);
577 const auto& future = iface.future ();
578 ThisFuture_ = future;
655 detail::EmptyDestructionTag
657 Sequence (QObject *parent,
const QFuture<T>& future)
676 QFutureInterface<T> iface;
677 iface.reportStarted ();
678 iface.reportFinished (&t);
679 return iface.future ();
QtConcurrent::Exception QtException_t
A proxy object allowing type-checked sequencing of actions and responsible for starting the initial a...
void Start()
Starts the first action in the chain.
auto operator>>(const MV &value, const F &f) -> decltype(Bind(value, f))
EnableIf_t<!std::is_same< R, void >::value > ReportFutureResult(QFutureInterface< R > &iface, F &&f, Args &&...args)
typename UnwrapFutureType< T >::type UnwrapFutureType_t
constexpr bool IsCompatible()
void Then(const std::function< void()> &action)
Sequencer(const Future &future, QObject *parent)
Constructs the sequencer.
auto Then(F &&f) -> EnableIf_t< std::is_same< void, decltype(f(std::declval< Ret >()))>::value >
Adds the funtor f to the chain of actions and closes the chain.
UnwrapFutureType_t< Future > RetType_t
The type instantinating the QFuture returned by the Executor.
SequenceProxy< Ret, Future, ResultOf_t< F()> > DestructionValue(F &&f)
constexpr bool IsCompatibleImpl(int)
void Then(const std::function< QFuture< RetT >(ArgT)> &action)
Chains the given asynchronous action.
Incapsulates the sequencing logic of asynchronous actions.
SequenceProxy(Sequencer< Future > *sequencer)
Constructs a sequencer proxy managing the given sequencer.
typename Sequencer< T >::RetType_t SequencerRetType_t
typename std::enable_if< B, T >::type EnableIf_t
Executes a given functor upon a signal (or a list of signals).
auto Then(F &&f) -> SequenceProxy< UnwrapFutureType_t< decltype(f(std::declval< Ret >()))>, Future, DestructionTag >
Adds the functor f to the chain of actions.
void InvokeDestructionHandler(const std::function< DestrType()> &, QFutureInterface< Ret > &, float)
auto Then(F &&f) -> EnableIf_t< std::is_same< void, Ret >::value &&std::is_same< void, decltype(f())>::value >
A concurrent exception that plays nicely with Qt.
void ExecuteFuture(Executor f, ResultHandler rh, QObject *parent, Args...args)
Runs a QFuture-returning function and feeding the future to a handler when it is ready.
QFuture< T > MakeReadyFuture(const T &t)
Creates a ready future holding the given value.
detail::SequenceProxy< detail::SequencerRetType_t< QFuture< T > >, QFuture< T >, detail::EmptyDestructionTag > Sequence(QObject *parent, const QFuture< T > &future)
Creates a sequencer that allows chaining multiple futures.
auto Invoke(F &&f, Args &&...args) -> decltype(std::forward< F >(f)(std::forward< Args >(args)...))
void Then(const std::function< void(ArgT)> &action)
Chains the given asynchronous action and closes the chain.
constexpr bool IsCompatibleImplVoid(int)
std::is_same< EmptyDestructionTag, T > IsEmptyDestr_t