11 #include <type_traits>
15 #include <QFutureInterface>
16 #include <QFutureWatcher>
24 template<
typename R,
typename F,
typename... Args>
29 constexpr
bool isVoid = std::is_same_v<R, void>;
30 if constexpr (!isVoid && !std::is_invocable_v<std::decay_t<F>, Args...>)
32 static_assert (std::is_constructible_v<R, F>);
33 static_assert (
sizeof... (Args) == 0,
34 "Extra args when a value is passed. Perhaps you wanted to pass in a function?");
36 const R result { std::forward<F> (
f) };
37 iface.reportResult (result);
39 else if constexpr (!isVoid)
41 const auto result = std::invoke (std::forward<F> (
f), std::forward<Args> (args)...);
42 iface.reportResult (result);
45 std::invoke (std::forward<F> (
f), std::forward<Args> (args)...);
49 iface.reportException (e);
51 catch (
const std::exception& e)
56 iface.reportFinished ();
62 struct UnwrapFutureTypeBase {};
65 struct UnwrapFutureTypeBase<
QFuture<T>>
71 struct UnwrapFutureType : UnwrapFutureTypeBase<std::decay_t<T>>
77 using UnwrapFutureType_t =
typename detail::UnwrapFutureType<T>::type;
90 template<
typename Future>
91 class Sequencer final :
public QObject
97 using RetType_t = UnwrapFutureType_t<Future>;
100 QFutureWatcher<RetType_t> BaseWatcher_;
101 QFutureWatcherBase *LastWatcher_ = &BaseWatcher_;
108 Sequencer (
const Future& future, QObject *parent)
111 , BaseWatcher_ {
this }
122 connect (LastWatcher_,
123 &QFutureWatcherBase::finished,
125 &QObject::deleteLater);
126 BaseWatcher_.setFuture (Future_);
149 template<
typename RetT,
typename ArgT>
150 void Then (
const std::function<
QFuture<RetT> (ArgT)>& action)
152 const auto last =
dynamic_cast<QFutureWatcher<ArgT>*
> (LastWatcher_);
156 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
159 const auto watcher =
new QFutureWatcher<RetT> {
this };
160 LastWatcher_ = watcher;
162 new SlotClosure<DeleteLaterPolicy>
164 [
this, last, watcher, action]
166 if (
static_cast<QObject*
> (last) != &BaseWatcher_)
167 last->deleteLater ();
168 watcher->setFuture (action (last->result ()));
171 SIGNAL (finished ()),
196 template<
typename ArgT>
197 void Then (
const std::function<
void (ArgT)>& action)
199 const auto last =
dynamic_cast<QFutureWatcher<ArgT>*
> (LastWatcher_);
203 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
206 new SlotClosure<DeleteLaterPolicy>
210 action (last->result ());
213 SIGNAL (finished ()),
218 void Then (
const std::function<
void ()>& action)
220 const auto last =
dynamic_cast<QFutureWatcher<void>*
> (LastWatcher_);
224 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
227 new SlotClosure<DeleteLaterPolicy>
231 SIGNAL (finished ()),
236 template<
typename Handler>
237 void MultipleResults (
const Handler& handler,
238 const std::function<
void ()>& finishHandler = {},
239 const std::function<void ()>& startHandler = {})
241 if (LastWatcher_ != &BaseWatcher_)
243 qWarning () << Q_FUNC_INFO
244 <<
"multiple results handler should be chained directly to the source";
245 throw std::runtime_error {
"invalid multiple results handler chaining" };
248 connect (&BaseWatcher_,
249 &QFutureWatcherBase::resultReadyAt,
251 [handler,
this] (
int index) { handler (BaseWatcher_.resultAt (index)); });
254 new Util::SlotClosure<Util::DeleteLaterPolicy>
258 SIGNAL (finished ()),
263 new Util::SlotClosure<Util::DeleteLaterPolicy>
271 connect (&BaseWatcher_,
272 SIGNAL (finished ()),
274 SLOT (deleteLater ()));
281 struct EmptyDestructionTag;
299 template<
typename Ret,
typename Future,
typename DestructionTag>
302 template<
typename,
typename,
typename>
303 friend class SequenceProxy;
305 std::shared_ptr<void> ExecuteGuard_;
306 Sequencer<Future> *
const Seq_;
308 std::optional<QFuture<Ret>> ThisFuture_;
310 std::function<DestructionTag ()> DestrHandler_;
312 SequenceProxy (
const std::shared_ptr<void>& guard, Sequencer<Future> *seq,
313 const std::function<DestructionTag ()>& destrHandler)
314 : ExecuteGuard_ { guard }
316 , DestrHandler_ { destrHandler }
320 template<
typename F1,
typename Ret1>
321 using ReturnsFutureDetector_t = UnwrapFutureType_t<std::result_of_t<F1 (Ret1)>>;
323 template<
typename F,
typename... Args>
324 using ReturnsVoidDetector_t = std::result_of_t<F (Args...)>;
333 SequenceProxy (Sequencer<Future> *sequencer)
334 : ExecuteGuard_ {
nullptr, [sequencer] (
void*) { sequencer->Start (); } }
344 SequenceProxy (
const SequenceProxy& proxy) =
delete;
351 SequenceProxy (SequenceProxy&& proxy) =
default;
363 throw std::runtime_error {
"SequenceProxy::Then(): cannot chain more after being converted to a QFuture" };
365 if constexpr (IsDetected_v<ReturnsFutureDetector_t, F, Ret>)
367 using Next_t = UnwrapFutureType_t<decltype (f (std::declval<Ret> ()))>;
368 Seq_->template Then<Next_t, Ret> (
f);
369 return SequenceProxy<Next_t, Future, DestructionTag> { ExecuteGuard_, Seq_, DestrHandler_ };
371 else if constexpr (std::is_same<IsDetected_t<struct Dummy, ReturnsVoidDetector_t, F, Ret>,
void> {})
372 Seq_->template Then<Ret> (
f);
373 else if constexpr (std::is_same<void, Ret>::value &&
374 std::is_same<IsDetected_t<struct Dummy, ReturnsVoidDetector_t, F>,
void> {})
375 Seq_->Then (std::function<void ()> {
f });
377 static_assert (std::is_same<F, struct Dummy> {},
"Invalid functor passed to SequenceProxy::Then()");
381 auto operator>> (F&&
f) -> decltype (this->Then (std::forward<F> (
f)))
383 return Then (std::forward<F> (
f));
387 SequenceProxy<Ret, Future, std::result_of_t<F ()>> DestructionValue (F&&
f)
389 static_assert (std::is_same<DestructionTag, EmptyDestructionTag>::value,
390 "Destruction handling function has been already set.");
392 return { ExecuteGuard_, Seq_, std::forward<F> (
f) };
396 void MultipleResults (F&&
f)
398 Seq_->MultipleResults (std::forward<F> (
f));
401 template<
typename F,
typename Finish>
402 void MultipleResults (F&&
f, Finish&& finish)
404 Seq_->MultipleResults (std::forward<F> (
f),
405 std::forward<Finish> (finish));
408 template<
typename F,
typename Finish,
typename Start>
409 void MultipleResults (F&&
f, Finish&& finish, Start&& start)
411 Seq_->MultipleResults (std::forward<F> (
f),
412 std::forward<Finish> (finish),
413 std::forward<Start> (start));
418 constexpr
bool isEmptyDestr = std::is_same<DestructionTag, EmptyDestructionTag>::value;
419 static_assert (std::is_same<DestructionTag, Ret>::value || isEmptyDestr,
420 "Destruction handler's return type doesn't match expected future type.");
426 iface.reportStarted ();
428 SlotClosure<DeleteLaterPolicy> *deleteGuard =
nullptr;
429 if constexpr (!isEmptyDestr)
431 deleteGuard =
new SlotClosure<DeleteLaterPolicy>
433 [destrHandler = DestrHandler_, iface] ()
mutable
435 if (iface.isFinished ())
438 const auto res = destrHandler ();
439 iface.reportFinished (&res);
442 SIGNAL (destroyed ()),
447 Then ([deleteGuard, iface] (
const Ret& ret)
mutable
449 iface.reportFinished (&ret);
454 const auto& future = iface.future ();
455 ThisFuture_ = future;
527 detail::SequenceProxy<
528 detail::SequencerRetType_t<QFuture<T>>,
530 detail::EmptyDestructionTag
532 Sequence (QObject *parent,
const QFuture<T>& future)
534 return {
new detail::Sequencer<QFuture<T>> { future, parent } };
552 iface.reportStarted ();
553 iface.reportFinished (&t);
554 return iface.future ();