15#include <QFutureInterface>
16#include <QFutureWatcher>
25 template<
typename R,
typename F = R,
typename... Args>
26 void ReportFutureResult (QFutureInterface<R>& iface, F&& f, Args&&... args)
30 constexpr bool isVoid = std::is_same_v<R, void>;
31 if constexpr (!isVoid && !std::is_invocable_v<std::decay_t<F>, Args...>)
33 static_assert (std::is_constructible_v<R, F>);
34 static_assert (
sizeof... (Args) == 0,
35 "Extra args when a value is passed. Perhaps you wanted to pass in a function?");
37 const R result { std::forward<F> (f) };
38 iface.reportResult (result);
40 else if constexpr (!isVoid)
42 const auto result = std::invoke (std::forward<F> (f), std::forward<Args> (args)...);
43 iface.reportResult (result);
46 std::invoke (std::forward<F> (f), std::forward<Args> (args)...);
50 iface.reportException (e);
52 catch (
const std::exception& e)
57 iface.reportFinished ();
63 struct UnwrapFutureTypeBase {};
66 struct UnwrapFutureTypeBase<QFuture<T>>
72 struct UnwrapFutureType : UnwrapFutureTypeBase<std::decay_t<T>>
78 using UnwrapFutureType_t =
typename detail::UnwrapFutureType<T>::type;
91 template<
typename Future>
92 class Sequencer final :
public QObject
98 using RetType_t = UnwrapFutureType_t<Future>;
101 QFutureWatcher<RetType_t> BaseWatcher_;
102 QFutureWatcherBase *LastWatcher_ = &BaseWatcher_;
109 Sequencer (
const Future& future, QObject *parent)
112 , BaseWatcher_ { this }
123 connect (LastWatcher_,
124 &QFutureWatcherBase::finished,
126 &QObject::deleteLater);
127 BaseWatcher_.setFuture (Future_);
150 template<
typename RetT,
typename ArgT>
151 void Then (
const std::function<QFuture<RetT> (ArgT)>& action)
153 const auto last =
dynamic_cast<QFutureWatcher<ArgT>*
> (LastWatcher_);
157 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
160 const auto watcher =
new QFutureWatcher<RetT> {
this };
161 LastWatcher_ = watcher;
163 new SlotClosure<DeleteLaterPolicy>
165 [
this, last, watcher, action]
167 if (
static_cast<QObject*
> (last) != &BaseWatcher_)
168 last->deleteLater ();
169 watcher->setFuture (action (last->result ()));
172 SIGNAL (finished ()),
197 template<
typename ArgT>
198 void Then (
const std::function<
void (ArgT)>& action)
200 const auto last =
dynamic_cast<QFutureWatcher<ArgT>*
> (LastWatcher_);
204 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
207 new SlotClosure<DeleteLaterPolicy>
211 action (last->result ());
214 SIGNAL (finished ()),
219 void Then (
const std::function<
void ()>& action)
221 const auto last =
dynamic_cast<QFutureWatcher<void>*
> (LastWatcher_);
225 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
228 new SlotClosure<DeleteLaterPolicy>
232 SIGNAL (finished ()),
237 template<
typename Handler>
238 void MultipleResults (
const Handler& handler,
239 const std::function<
void ()>& finishHandler = {},
240 const std::function<void ()>& startHandler = {})
242 if (LastWatcher_ != &BaseWatcher_)
244 qWarning () << Q_FUNC_INFO
245 <<
"multiple results handler should be chained directly to the source";
246 throw std::runtime_error {
"invalid multiple results handler chaining" };
249 connect (&BaseWatcher_,
250 &QFutureWatcherBase::resultReadyAt,
252 [handler,
this] (
int index) { handler (BaseWatcher_.resultAt (index)); });
255 new Util::SlotClosure<Util::DeleteLaterPolicy>
259 SIGNAL (finished ()),
264 new Util::SlotClosure<Util::DeleteLaterPolicy>
272 connect (&BaseWatcher_,
273 SIGNAL (finished ()),
275 SLOT (deleteLater ()));
280 using SequencerRetType_t =
typename Sequencer<T>::RetType_t;
282 struct EmptyDestructionTag;
300 template<
typename Ret,
typename Future,
typename DestructionTag>
303 template<
typename,
typename,
typename>
304 friend class SequenceProxy;
306 std::shared_ptr<void> ExecuteGuard_;
307 Sequencer<Future> *
const Seq_;
309 std::optional<QFuture<Ret>> ThisFuture_;
311 std::function<DestructionTag ()> DestrHandler_;
313 SequenceProxy (
const std::shared_ptr<void>& guard, Sequencer<Future> *seq,
314 const std::function<DestructionTag ()>& destrHandler)
315 : ExecuteGuard_ { guard }
317 , DestrHandler_ { destrHandler }
321 template<
typename F1,
typename Ret1>
322 using ReturnsFutureDetector_t = UnwrapFutureType_t<std::invoke_result_t<F1, Ret1>>;
324 template<
typename F,
typename... Args>
325 using ReturnsVoidDetector_t = std::invoke_result_t<F, Args...>;
334 SequenceProxy (Sequencer<Future> *sequencer)
335 : ExecuteGuard_ { nullptr, [sequencer] (void*) { sequencer->Start (); } }
345 SequenceProxy (
const SequenceProxy& proxy) =
delete;
352 SequenceProxy (SequenceProxy&& proxy) =
default;
364 throw std::runtime_error {
"SequenceProxy::Then(): cannot chain more after being converted to a QFuture" };
368 using Next_t = UnwrapFutureType_t<decltype (f (std::declval<Ret> ()))>;
369 Seq_->template Then<Next_t, Ret> (f);
370 return SequenceProxy<Next_t, Future, DestructionTag> { ExecuteGuard_, Seq_, DestrHandler_ };
372 else if constexpr (std::is_same<IsDetected_t<struct Dummy, ReturnsVoidDetector_t, F, Ret>,
void> {})
373 Seq_->template Then<Ret> (f);
374 else if constexpr (std::is_same<void, Ret>::value &&
375 std::is_same<IsDetected_t<struct Dummy, ReturnsVoidDetector_t, F>,
void> {})
376 Seq_->Then (std::function<void ()> {
f });
378 static_assert (std::is_same<F, struct Dummy> {},
"Invalid functor passed to SequenceProxy::Then()");
382 auto operator>> (F&& f) ->
decltype (this->Then (std::forward<F> (f)))
384 return Then (std::forward<F> (f));
388 SequenceProxy<Ret, Future, std::invoke_result_t<F>> DestructionValue (F&& f)
390 static_assert (std::is_same<DestructionTag, EmptyDestructionTag>::value,
391 "Destruction handling function has been already set.");
393 return { ExecuteGuard_, Seq_, std::forward<F> (f) };
397 void MultipleResults (F&& f)
399 Seq_->MultipleResults (std::forward<F> (f));
402 template<
typename F,
typename Finish>
403 void MultipleResults (F&& f, Finish&& finish)
405 Seq_->MultipleResults (std::forward<F> (f),
406 std::forward<Finish> (finish));
409 template<
typename F,
typename Finish,
typename Start>
410 void MultipleResults (F&& f, Finish&& finish, Start&& start)
412 Seq_->MultipleResults (std::forward<F> (f),
413 std::forward<Finish> (finish),
414 std::forward<Start> (start));
417 operator QFuture<Ret> ()
419 constexpr bool isEmptyDestr = std::is_same<DestructionTag, EmptyDestructionTag>::value;
420 static_assert (std::is_same<DestructionTag, Ret>::value || isEmptyDestr,
421 "Destruction handler's return type doesn't match expected future type.");
426 QFutureInterface<Ret> iface;
427 iface.reportStarted ();
429 SlotClosure<DeleteLaterPolicy> *deleteGuard =
nullptr;
430 if constexpr (!isEmptyDestr)
432 deleteGuard =
new SlotClosure<DeleteLaterPolicy>
434 [destrHandler = DestrHandler_, iface] ()
mutable
436 if (iface.isFinished ())
439 const auto res = destrHandler ();
440 iface.reportFinished (&res);
443 SIGNAL (destroyed ()),
448 Then ([deleteGuard, iface] (
const Ret& ret)
mutable
450 iface.reportFinished (&ret);
455 const auto& future = iface.future ();
456 ThisFuture_ = future;
528 detail::SequenceProxy<
529 detail::SequencerRetType_t<QFuture<T>>,
531 detail::EmptyDestructionTag
533 Sequence (QObject *parent,
const QFuture<T>& future)
535 return {
new detail::Sequencer<QFuture<T>> { future, parent } };
552 QFutureInterface<T> iface;
553 iface.reportStarted ();
554 iface.reportFinished (&t);
555 return iface.future ();
const QDBusArgument & operator>>(const QDBusArgument &in, IconFrame &frame)
constexpr detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, detail::MemberPtrs< Ptr > > f
constexpr bool IsDetected_v
std::tuple_element_t< 0, detail::CallTypeGetter_t< F > > RetType_t
Util::ConcurrentException< Util::NewType< std::exception, struct StdException > > ConcurrentStdException