32 #include <type_traits> 35 #include <boost/optional.hpp> 36 #include <QFutureInterface> 37 #include <QFutureWatcher> 47 template<
typename R,
typename F,
typename... Args>
52 constexpr
bool isVoid = std::is_same_v<R, void>;
53 if constexpr (!isVoid && !std::is_invocable_v<std::decay_t<F>, Args...>)
55 static_assert (std::is_constructible_v<R, F>);
56 static_assert (
sizeof... (Args) == 0,
57 "Extra args when a value is passed. Perhaps you wanted to pass in a function?");
59 const R result { std::forward<F> (
f) };
60 iface.reportResult (result);
62 else if constexpr (!isVoid)
64 const auto result = std::invoke (std::forward<F> (
f), std::forward<Args> (args)...);
65 iface.reportResult (result);
68 std::invoke (std::forward<F> (
f), std::forward<Args> (args)...);
72 iface.reportException (e);
74 catch (
const std::exception& e)
79 iface.reportFinished ();
85 struct UnwrapFutureTypeBase {};
88 struct UnwrapFutureTypeBase<
QFuture<T>>
94 struct UnwrapFutureType : UnwrapFutureTypeBase<std::decay_t<T>>
100 using UnwrapFutureType_t =
typename detail::UnwrapFutureType<T>::type;
113 template<
typename Future>
114 class Sequencer final :
public QObject
120 using RetType_t = UnwrapFutureType_t<Future>;
123 QFutureWatcher<RetType_t> BaseWatcher_;
124 QFutureWatcherBase *LastWatcher_ = &BaseWatcher_;
131 Sequencer (
const Future& future, QObject *parent)
134 , BaseWatcher_ {
this }
145 connect (LastWatcher_,
146 &QFutureWatcherBase::finished,
148 &QObject::deleteLater);
149 BaseWatcher_.setFuture (Future_);
172 template<
typename RetT,
typename ArgT>
173 void Then (
const std::function<
QFuture<RetT> (ArgT)>& action)
175 const auto last =
dynamic_cast<QFutureWatcher<ArgT>*
> (LastWatcher_);
179 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
182 const auto watcher =
new QFutureWatcher<RetT> {
this };
183 LastWatcher_ = watcher;
185 new SlotClosure<DeleteLaterPolicy>
187 [
this, last, watcher, action]
189 if (static_cast<QObject*> (last) != &BaseWatcher_)
190 last->deleteLater ();
191 watcher->setFuture (action (last->result ()));
194 SIGNAL (finished ()),
219 template<
typename ArgT>
220 void Then (
const std::function<
void (ArgT)>& action)
222 const auto last =
dynamic_cast<QFutureWatcher<ArgT>*
> (LastWatcher_);
226 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
229 new SlotClosure<DeleteLaterPolicy>
233 action (last->result ());
236 SIGNAL (finished ()),
241 void Then (
const std::function<
void ()>& action)
243 const auto last =
dynamic_cast<QFutureWatcher<void>*
> (LastWatcher_);
247 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
250 new SlotClosure<DeleteLaterPolicy>
254 SIGNAL (finished ()),
259 template<
typename Handler>
260 void MultipleResults (
const Handler& handler,
261 const std::function<
void ()>& finishHandler = {},
262 const std::function<void ()>& startHandler = {})
264 if (LastWatcher_ != &BaseWatcher_)
266 qWarning () << Q_FUNC_INFO
267 <<
"multiple results handler should be chained directly to the source";
268 throw std::runtime_error {
"invalid multiple results handler chaining" };
271 connect (&BaseWatcher_,
272 &QFutureWatcherBase::resultReadyAt,
274 [handler,
this] (
int index) { handler (BaseWatcher_.resultAt (index)); });
277 new Util::SlotClosure<Util::DeleteLaterPolicy>
281 SIGNAL (finished ()),
286 new Util::SlotClosure<Util::DeleteLaterPolicy>
294 connect (&BaseWatcher_,
295 SIGNAL (finished ()),
297 SLOT (deleteLater ()));
304 struct EmptyDestructionTag;
322 template<
typename Ret,
typename Future,
typename DestructionTag>
325 template<
typename,
typename,
typename>
326 friend class SequenceProxy;
328 std::shared_ptr<void> ExecuteGuard_;
329 Sequencer<Future> *
const Seq_;
331 boost::optional<QFuture<Ret>> ThisFuture_;
333 std::function<DestructionTag ()> DestrHandler_;
335 SequenceProxy (
const std::shared_ptr<void>& guard, Sequencer<Future> *seq,
336 const std::function<DestructionTag ()>& destrHandler)
337 : ExecuteGuard_ { guard }
339 , DestrHandler_ { destrHandler }
343 template<
typename F1,
typename Ret1>
344 using ReturnsFutureDetector_t = UnwrapFutureType_t<std::result_of_t<F1 (Ret1)>>;
346 template<
typename F,
typename... Args>
347 using ReturnsVoidDetector_t = std::result_of_t<F (Args...)>;
356 SequenceProxy (Sequencer<Future> *sequencer)
357 : ExecuteGuard_ {
nullptr, [sequencer] (
void*) { sequencer->Start (); } }
367 SequenceProxy (
const SequenceProxy& proxy) =
delete;
374 SequenceProxy (SequenceProxy&& proxy) =
default;
386 throw std::runtime_error {
"SequenceProxy::Then(): cannot chain more after being converted to a QFuture" };
388 if constexpr (IsDetected_v<ReturnsFutureDetector_t, F, Ret>)
390 using Next_t = UnwrapFutureType_t<decltype (f (std::declval<Ret> ()))>;
391 Seq_->template Then<Next_t, Ret> (
f);
392 return SequenceProxy<Next_t, Future, DestructionTag> { ExecuteGuard_, Seq_, DestrHandler_ };
394 else if constexpr (std::is_same<IsDetected_t<struct Dummy, ReturnsVoidDetector_t, F, Ret>,
void> {})
395 Seq_->template Then<Ret> (
f);
396 else if constexpr (std::is_same<void, Ret>::value &&
397 std::is_same<IsDetected_t<struct Dummy, ReturnsVoidDetector_t, F>,
void> {})
398 Seq_->Then (std::function<void ()> {
f });
400 static_assert (std::is_same<F, struct Dummy> {},
"Invalid functor passed to SequenceProxy::Then()");
404 auto operator>> (F&&
f) -> decltype (this->Then (std::forward<F> (
f)))
406 return Then (std::forward<F> (
f));
410 SequenceProxy<Ret, Future, std::result_of_t<F ()>> DestructionValue (F&&
f)
412 static_assert (std::is_same<DestructionTag, EmptyDestructionTag>::value,
413 "Destruction handling function has been already set.");
415 return { ExecuteGuard_, Seq_, std::forward<F> (
f) };
419 void MultipleResults (F&&
f)
421 Seq_->MultipleResults (std::forward<F> (
f));
424 template<
typename F,
typename Finish>
425 void MultipleResults (F&&
f, Finish&& finish)
427 Seq_->MultipleResults (std::forward<F> (
f),
428 std::forward<Finish> (finish));
431 template<
typename F,
typename Finish,
typename Start>
432 void MultipleResults (F&&
f, Finish&& finish, Start&& start)
434 Seq_->MultipleResults (std::forward<F> (
f),
435 std::forward<Finish> (finish),
436 std::forward<Start> (start));
441 constexpr
bool isEmptyDestr = std::is_same<DestructionTag, EmptyDestructionTag>::value;
442 static_assert (std::is_same<DestructionTag, Ret>::value || isEmptyDestr,
443 "Destruction handler's return type doesn't match expected future type.");
449 iface.reportStarted ();
451 SlotClosure<DeleteLaterPolicy> *deleteGuard =
nullptr;
452 if constexpr (!isEmptyDestr)
454 deleteGuard =
new SlotClosure<DeleteLaterPolicy>
456 [destrHandler = DestrHandler_, iface] ()
mutable 458 if (iface.isFinished ())
461 const auto res = destrHandler ();
462 iface.reportFinished (&res);
465 SIGNAL (destroyed ()),
470 Then ([deleteGuard, iface] (
const Ret& ret)
mutable 472 iface.reportFinished (&ret);
477 const auto& future = iface.future ();
478 ThisFuture_ = future;
550 detail::SequenceProxy<
551 detail::SequencerRetType_t<QFuture<T>>,
553 detail::EmptyDestructionTag
555 Sequence (QObject *parent,
const QFuture<T>& future)
557 return {
new detail::Sequencer<QFuture<T>> { future, parent } };
575 iface.reportStarted ();
576 iface.reportFinished (&t);
577 return iface.future ();
auto operator>>(const MV &value, const F &f) -> decltype(Bind(value, f))
constexpr detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, detail::MemberPtrs< Ptr > > f
Util::ConcurrentException< Util::NewType< std::exception, 0, __LINE__ > > ConcurrentStdException
std::conditional_t< std::is_same_v< detail::RetTypeRaw_t< F >, detail::ReturnsVoid >, void, detail::RetTypeRaw_t< F > > RetType_t