32 #include <type_traits> 35 #include <boost/optional.hpp> 36 #include <QFutureInterface> 37 #include <QFutureWatcher> 49 template<
typename T,
typename... Args>
50 using CallableDetector_t = std::result_of_t<T (Args...)>;
53 template<
typename R,
typename F,
typename... Args>
58 constexpr
bool isVoid = std::is_same<R, void> {};
59 if constexpr (!isVoid && !
IsDetected_v<detail::CallableDetector_t, std::decay_t<F>, Args...>)
61 static_assert (std::is_constructible<R, F> {});
62 static_assert (
sizeof... (Args) == 0,
63 "Extra args when a value is passed. Perhaps you wanted to pass in a function?");
65 const R result { std::forward<F> (
f) };
66 iface.reportResult (result);
68 else if constexpr (!isVoid)
70 const auto result = std::invoke (std::forward<F> (
f), std::forward<Args> (args)...);
71 iface.reportResult (result);
74 std::invoke (std::forward<F> (
f), std::forward<Args> (args)...);
78 iface.reportException (e);
80 catch (
const std::exception& e)
85 iface.reportFinished ();
91 struct UnwrapFutureTypeBase {};
94 struct UnwrapFutureTypeBase<
QFuture<T>>
100 struct UnwrapFutureType : UnwrapFutureTypeBase<std::decay_t<T>>
106 using UnwrapFutureType_t =
typename detail::UnwrapFutureType<T>::type;
119 template<
typename Future>
120 class Sequencer final :
public QObject
126 using RetType_t = UnwrapFutureType_t<Future>;
129 QFutureWatcher<RetType_t> BaseWatcher_;
130 QFutureWatcherBase *LastWatcher_ = &BaseWatcher_;
137 Sequencer (
const Future& future, QObject *parent)
140 , BaseWatcher_ {
this }
151 connect (LastWatcher_,
152 &QFutureWatcherBase::finished,
154 &QObject::deleteLater);
155 BaseWatcher_.setFuture (Future_);
178 template<
typename RetT,
typename ArgT>
179 void Then (
const std::function<
QFuture<RetT> (ArgT)>& action)
181 const auto last =
dynamic_cast<QFutureWatcher<ArgT>*
> (LastWatcher_);
185 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
188 const auto watcher =
new QFutureWatcher<RetT> {
this };
189 LastWatcher_ = watcher;
191 new SlotClosure<DeleteLaterPolicy>
193 [
this, last, watcher, action]
195 if (static_cast<QObject*> (last) != &BaseWatcher_)
196 last->deleteLater ();
197 watcher->setFuture (action (last->result ()));
200 SIGNAL (finished ()),
225 template<
typename ArgT>
226 void Then (
const std::function<
void (ArgT)>& action)
228 const auto last =
dynamic_cast<QFutureWatcher<ArgT>*
> (LastWatcher_);
232 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
235 new SlotClosure<DeleteLaterPolicy>
239 action (last->result ());
242 SIGNAL (finished ()),
247 void Then (
const std::function<
void ()>& action)
249 const auto last =
dynamic_cast<QFutureWatcher<void>*
> (LastWatcher_);
253 throw std::runtime_error { std::string {
"invalid type in " } + Q_FUNC_INFO };
256 new SlotClosure<DeleteLaterPolicy>
260 SIGNAL (finished ()),
265 template<
typename Handler>
266 void MultipleResults (
const Handler& handler,
267 const std::function<
void ()>& finishHandler = {},
268 const std::function<void ()>& startHandler = {})
270 if (LastWatcher_ != &BaseWatcher_)
272 qWarning () << Q_FUNC_INFO
273 <<
"multiple results handler should be chained directly to the source";
274 throw std::runtime_error {
"invalid multiple results handler chaining" };
277 connect (&BaseWatcher_,
278 &QFutureWatcherBase::resultReadyAt,
280 [handler,
this] (
int index) { handler (BaseWatcher_.resultAt (index)); });
283 new Util::SlotClosure<Util::DeleteLaterPolicy>
287 SIGNAL (finished ()),
292 new Util::SlotClosure<Util::DeleteLaterPolicy>
300 connect (&BaseWatcher_,
301 SIGNAL (finished ()),
303 SLOT (deleteLater ()));
310 struct EmptyDestructionTag;
328 template<
typename Ret,
typename Future,
typename DestructionTag>
331 template<
typename,
typename,
typename>
332 friend class SequenceProxy;
334 std::shared_ptr<void> ExecuteGuard_;
335 Sequencer<Future> *
const Seq_;
337 boost::optional<QFuture<Ret>> ThisFuture_;
339 std::function<DestructionTag ()> DestrHandler_;
341 SequenceProxy (
const std::shared_ptr<void>& guard, Sequencer<Future> *seq,
342 const std::function<DestructionTag ()>& destrHandler)
343 : ExecuteGuard_ { guard }
345 , DestrHandler_ { destrHandler }
349 template<
typename F1,
typename Ret1>
350 using ReturnsFutureDetector_t = UnwrapFutureType_t<std::result_of_t<F1 (Ret1)>>;
352 template<
typename F,
typename... Args>
353 using ReturnsVoidDetector_t = std::result_of_t<F (Args...)>;
362 SequenceProxy (Sequencer<Future> *sequencer)
363 : ExecuteGuard_ {
nullptr, [sequencer] (
void*) { sequencer->Start (); } }
373 SequenceProxy (
const SequenceProxy& proxy) =
delete;
380 SequenceProxy (SequenceProxy&& proxy) =
default;
392 throw std::runtime_error {
"SequenceProxy::Then(): cannot chain more after being converted to a QFuture" };
394 if constexpr (IsDetected_v<ReturnsFutureDetector_t, F, Ret>)
396 using Next_t = UnwrapFutureType_t<decltype (f (std::declval<Ret> ()))>;
397 Seq_->template Then<Next_t, Ret> (
f);
398 return SequenceProxy<Next_t, Future, DestructionTag> { ExecuteGuard_, Seq_, DestrHandler_ };
400 else if constexpr (std::is_same<IsDetected_t<struct Dummy, ReturnsVoidDetector_t, F, Ret>,
void> {})
401 Seq_->template Then<Ret> (
f);
402 else if constexpr (std::is_same<void, Ret>::value &&
403 std::is_same<IsDetected_t<struct Dummy, ReturnsVoidDetector_t, F>,
void> {})
404 Seq_->Then (std::function<void ()> {
f });
406 static_assert (std::is_same<F, struct Dummy> {},
"Invalid functor passed to SequenceProxy::Then()");
410 auto operator>> (F&&
f) -> decltype (this->Then (std::forward<F> (
f)))
412 return Then (std::forward<F> (
f));
416 SequenceProxy<Ret, Future, std::result_of_t<F ()>> DestructionValue (F&&
f)
418 static_assert (std::is_same<DestructionTag, EmptyDestructionTag>::value,
419 "Destruction handling function has been already set.");
421 return { ExecuteGuard_, Seq_, std::forward<F> (
f) };
425 void MultipleResults (F&&
f)
427 Seq_->MultipleResults (std::forward<F> (
f));
430 template<
typename F,
typename Finish>
431 void MultipleResults (F&&
f, Finish&& finish)
433 Seq_->MultipleResults (std::forward<F> (
f),
434 std::forward<Finish> (finish));
437 template<
typename F,
typename Finish,
typename Start>
438 void MultipleResults (F&&
f, Finish&& finish, Start&& start)
440 Seq_->MultipleResults (std::forward<F> (
f),
441 std::forward<Finish> (finish),
442 std::forward<Start> (start));
447 constexpr
bool isEmptyDestr = std::is_same<DestructionTag, EmptyDestructionTag>::value;
448 static_assert (std::is_same<DestructionTag, Ret>::value || isEmptyDestr,
449 "Destruction handler's return type doesn't match expected future type.");
455 iface.reportStarted ();
457 SlotClosure<DeleteLaterPolicy> *deleteGuard =
nullptr;
458 if constexpr (!isEmptyDestr)
460 deleteGuard =
new SlotClosure<DeleteLaterPolicy>
462 [destrHandler = DestrHandler_, iface] ()
mutable 464 if (iface.isFinished ())
467 const auto res = destrHandler ();
468 iface.reportFinished (&res);
471 SIGNAL (destroyed ()),
476 Then ([deleteGuard, iface] (
const Ret& ret)
mutable 478 iface.reportFinished (&ret);
483 const auto& future = iface.future ();
484 ThisFuture_ = future;
556 detail::SequenceProxy<
557 detail::SequencerRetType_t<QFuture<T>>,
559 detail::EmptyDestructionTag
561 Sequence (QObject *parent,
const QFuture<T>& future)
563 return {
new detail::Sequencer<QFuture<T>> { future, parent } };
581 iface.reportStarted ();
582 iface.reportFinished (&t);
583 return iface.future ();
constexpr detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, detail::MemberPtrs< Ptr > > f
auto operator>>(const MV &value, const F &f) -> decltype(Bind(value, f))
constexpr bool IsDetected_v
std::conditional_t< std::is_same_v< detail::RetTypeRaw_t< F >, detail::ReturnsVoid >, void, detail::RetTypeRaw_t< F > > RetType_t
Util::ConcurrentException< Util::NewType< std::exception, 0, __LINE__ > > ConcurrentStdException