Revision control

++ // Copyright (C) 2020 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #ifndef QFUTURE_H
++ #error Do not include qfuture_impl.h directly
++ #endif
++
++ #if 0
++ #pragma qt_sync_skip_header_check
++ #pragma qt_sync_stop_processing
++ #endif
++
++ #include <QtCore/qglobal.h>
++ #include <QtCore/qfunctionaltools_impl.h>
++ #include <QtCore/qfutureinterface.h>
++ #include <QtCore/qthreadpool.h>
++ #include <QtCore/qexception.h>
++ #include <QtCore/qpromise.h>
++ #include <QtCore/qvariant.h>
++
++ #include <memory>
++
++ QT_BEGIN_NAMESPACE
++
++ //
++ // forward declarations
++ //
++ template<class T>
++ class QFuture;
++ template<class T>
++ class QFutureInterface;
++ template<class T>
++ class QPromise;
++
++ namespace QtFuture {
++
++ enum class Launch { Sync, Async, Inherit };
++
++ template<class T>
++ struct WhenAnyResult
++ {
++ qsizetype index = -1;
++ QFuture<T> future;
++ };
++
++ // Deduction guide
++ template<class T>
++ WhenAnyResult(qsizetype, const QFuture<T> &) -> WhenAnyResult<T>;
++ }
++
++ namespace QtPrivate {
++
++ // implemented in qfutureinterface.cpp
++ Q_CORE_EXPORT void qfutureWarnIfUnusedResults(qsizetype numResults);
++
++ template<class T>
++ using EnableForVoid = std::enable_if_t<std::is_same_v<T, void>>;
++
++ template<class T>
++ using EnableForNonVoid = std::enable_if_t<!std::is_same_v<T, void>>;
++
++ template<typename F, typename Arg, typename Enable = void>
++ struct ResultTypeHelper
++ {
++ };
++
++ // The callable takes an argument of type Arg
++ template<typename F, typename Arg>
++ struct ResultTypeHelper<
++ F, Arg, typename std::enable_if_t<!std::is_invocable_v<std::decay_t<F>, QFuture<Arg>>>>
++ {
++ using ResultType = std::invoke_result_t<std::decay_t<F>, std::decay_t<Arg>>;
++ };
++
++ // The callable takes an argument of type QFuture<Arg>
++ template<class F, class Arg>
++ struct ResultTypeHelper<
++ F, Arg, typename std::enable_if_t<std::is_invocable_v<std::decay_t<F>, QFuture<Arg>>>>
++ {
++ using ResultType = std::invoke_result_t<std::decay_t<F>, QFuture<Arg>>;
++ };
++
++ // The callable takes an argument of type QFuture<void>
++ template<class F>
++ struct ResultTypeHelper<
++ F, void, typename std::enable_if_t<std::is_invocable_v<std::decay_t<F>, QFuture<void>>>>
++ {
++ using ResultType = std::invoke_result_t<std::decay_t<F>, QFuture<void>>;
++ };
++
++ // The callable doesn't take argument
++ template<class F>
++ struct ResultTypeHelper<
++ F, void, typename std::enable_if_t<!std::is_invocable_v<std::decay_t<F>, QFuture<void>>>>
++ {
++ using ResultType = std::invoke_result_t<std::decay_t<F>>;
++ };
++
++ // Helpers to remove QPrivateSignal argument from the list of arguments
++
++ template<class T, class Enable = void>
++ inline constexpr bool IsPrivateSignalArg = false;
++
++ template<class T>
++ inline constexpr bool IsPrivateSignalArg<T, typename std::enable_if_t<
++ // finds injected-class-name, the 'class' avoids falling into the rules of [class.qual]/2:
++ std::is_class_v<class T::QPrivateSignal>
++ >> = true;
++
++ template<class Tuple, std::size_t... I>
++ auto cutTuple(Tuple &&t, std::index_sequence<I...>)
++ {
++ return std::make_tuple(std::get<I>(t)...);
++ }
++
++ template<class Arg, class... Args>
++ auto createTuple(Arg &&arg, Args &&... args)
++ {
++ using TupleType = std::tuple<std::decay_t<Arg>, std::decay_t<Args>...>;
++ constexpr auto Size = sizeof...(Args); // One less than the size of all arguments
++ if constexpr (QtPrivate::IsPrivateSignalArg<std::tuple_element_t<Size, TupleType>>) {
++ if constexpr (Size == 1) {
++ return std::forward<Arg>(arg);
++ } else {
++ return cutTuple(std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...),
++ std::make_index_sequence<Size>());
++ }
++ } else {
++ return std::make_tuple(std::forward<Arg>(arg), std::forward<Args>(args)...);
++ }
++ }
++
++ // Helpers to resolve argument types of callables.
++
++ template<class Arg, class... Args>
++ using FilterLastPrivateSignalArg =
++ std::conditional_t<(sizeof...(Args) > 0),
++ std::invoke_result_t<decltype(createTuple<Arg, Args...>), Arg, Args...>,
++ std::conditional_t<IsPrivateSignalArg<Arg>, void, Arg>>;
++
++ template<typename...>
++ struct ArgsType;
++
++ template<typename Arg, typename... Args>
++ struct ArgsType<Arg, Args...>
++ {
++ using First = Arg;
++ using PromiseType = void;
++ using IsPromise = std::false_type;
++ static const bool HasExtraArgs = (sizeof...(Args) > 0);
++ using AllArgs = FilterLastPrivateSignalArg<std::decay_t<Arg>, std::decay_t<Args>...>;
++
++ template<class Class, class Callable>
++ static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class, Arg, Args...>;
++ };
++
++ template<typename Arg, typename... Args>
++ struct ArgsType<QPromise<Arg> &, Args...>
++ {
++ using First = QPromise<Arg> &;
++ using PromiseType = Arg;
++ using IsPromise = std::true_type;
++ static const bool HasExtraArgs = (sizeof...(Args) > 0);
++ using AllArgs = FilterLastPrivateSignalArg<QPromise<Arg>, std::decay_t<Args>...>;
++
++ template<class Class, class Callable>
++ static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class, QPromise<Arg> &, Args...>;
++ };
++
++ template<>
++ struct ArgsType<>
++ {
++ using First = void;
++ using PromiseType = void;
++ using IsPromise = std::false_type;
++ static const bool HasExtraArgs = false;
++ using AllArgs = void;
++
++ template<class Class, class Callable>
++ static const bool CanInvokeWithArgs = std::is_invocable_v<Callable, Class>;
++ };
++
++ template<typename F>
++ struct ArgResolver : ArgResolver<decltype(&std::decay_t<F>::operator())>
++ {
++ };
++
++ template<typename F>
++ struct ArgResolver<std::reference_wrapper<F>> : ArgResolver<decltype(&std::decay_t<F>::operator())>
++ {
++ };
++
++ template<typename R, typename... Args>
++ struct ArgResolver<R(Args...)> : public ArgsType<Args...>
++ {
++ };
++
++ template<typename R, typename... Args>
++ struct ArgResolver<R (*)(Args...)> : public ArgsType<Args...>
++ {
++ };
++
++ template<typename R, typename... Args>
++ struct ArgResolver<R (*&)(Args...)> : public ArgsType<Args...>
++ {
++ };
++
++ template<typename R, typename... Args>
++ struct ArgResolver<R (* const)(Args...)> : public ArgsType<Args...>
++ {
++ };
++
++ template<typename R, typename... Args>
++ struct ArgResolver<R (&)(Args...)> : public ArgsType<Args...>
++ {
++ };
++
++ template<typename Class, typename R, typename... Args>
++ struct ArgResolver<R (Class::*)(Args...)> : public ArgsType<Args...>
++ {
++ };
++
++ template<typename Class, typename R, typename... Args>
++ struct ArgResolver<R (Class::*)(Args...) noexcept> : public ArgsType<Args...>
++ {
++ };
++
++ template<typename Class, typename R, typename... Args>
++ struct ArgResolver<R (Class::*)(Args...) const> : public ArgsType<Args...>
++ {
++ };
++
++ template<typename Class, typename R, typename... Args>
++ struct ArgResolver<R (Class::*)(Args...) const noexcept> : public ArgsType<Args...>
++ {
++ };
++
++ template<typename Class, typename R, typename... Args>
++ struct ArgResolver<R (Class::* const)(Args...) const> : public ArgsType<Args...>
++ {
++ };
++
++ template<typename Class, typename R, typename... Args>
++ struct ArgResolver<R (Class::* const)(Args...) const noexcept> : public ArgsType<Args...>
++ {
++ };
++
++ template<class Class, class Callable>
++ using EnableIfInvocable = std::enable_if_t<
++ QtPrivate::ArgResolver<Callable>::template CanInvokeWithArgs<Class, Callable>>;
++
++ template<class T>
++ inline constexpr bool isQFutureV = false;
++
++ template<class T>
++ inline constexpr bool isQFutureV<QFuture<T>> = true;
++
++ template<class T>
++ using isQFuture = std::bool_constant<isQFutureV<T>>;
++
++ template<class T>
++ struct Future
++ {
++ };
++
++ template<class T>
++ struct Future<QFuture<T>>
++ {
++ using type = T;
++ };
++
++ template<class... Args>
++ using NotEmpty = std::bool_constant<(sizeof...(Args) > 0)>;
++
++ template<class Sequence>
++ using IsRandomAccessible =
++ std::is_convertible<typename std::iterator_traits<std::decay_t<decltype(
++ std::begin(std::declval<Sequence>()))>>::iterator_category,
++ std::random_access_iterator_tag>;
++
++ template<class Sequence>
++ using HasInputIterator =
++ std::is_convertible<typename std::iterator_traits<std::decay_t<decltype(
++ std::begin(std::declval<Sequence>()))>>::iterator_category,
++ std::input_iterator_tag>;
++
++ template<class Iterator>
++ using IsForwardIterable =
++ std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category,
++ std::forward_iterator_tag>;
++
++ template<typename Function, typename ResultType, typename ParentResultType>
++ class CompactContinuation : private CompactStorage<Function>
++ {
++ Q_DISABLE_COPY_MOVE(CompactContinuation)
++ public:
++ using Storage = CompactStorage<Function>;
++
++ template<typename F = Function>
++ CompactContinuation(F &&func, const QFuture<ParentResultType> &f, QPromise<ResultType> &&p)
++ : Storage{std::forward<F>(func)}, promise(std::move(p)), parentFuture(f), type(Type::Sync)
++ {
++ }
++
++ template<typename F = Function>
++ CompactContinuation(F &&func, const QFuture<ParentResultType> &f, QPromise<ResultType> &&p,
++ QThreadPool *pool)
++ : Storage{std::forward<F>(func)}, promise(std::move(p)), parentFuture(f),
++ threadPool(pool), type(Type::Async)
++ {
++ runObj = QRunnable::create([continuation = this] {
++ continuation->runFunction();
++ delete continuation;
++ });
++ runObj->setAutoDelete(false);
++ }
++
++ ~CompactContinuation() { delete runObj; }
++
++ bool execute();
++
++ QRunnable *runnable() const { return runObj; }
++
++ template<typename F = Function>
++ static void create(F &&func, QFuture<ParentResultType> *f, QFutureInterface<ResultType> &fi,
++ QtFuture::Launch policy);
++
++ template<typename F = Function>
++ static void create(F &&func, QFuture<ParentResultType> *f, QFutureInterface<ResultType> &fi,
++ QThreadPool *pool);
++
++ template<typename F = Function>
++ static void create(F &&func, QFuture<ParentResultType> *f, QFutureInterface<ResultType> &fi,
++ QObject *context);
++
++ private:
++ void fulfillPromiseWithResult();
++ void fulfillVoidPromise();
++ void fulfillPromiseWithVoidResult();
++
++ template<class... Args>
++ void fulfillPromise(Args &&... args);
++
++ protected:
++ void runImpl()
++ {
++ if (type == Type::Sync) {
++ runFunction();
++ } else {
++ Q_ASSERT(runObj);
++ QThreadPool *pool = threadPool ? threadPool : QThreadPool::globalInstance();
++ pool->start(runObj);
++ }
++ }
++
++ void runFunction();
++
++ protected:
++ enum class Type : quint8 {
++ Sync,
++ Async
++ };
++
++ QPromise<ResultType> promise;
++ QFuture<ParentResultType> parentFuture;
++ QThreadPool *threadPool = nullptr;
++ QRunnable *runObj = nullptr;
++ const Type type;
++ };
++
++ #ifndef QT_NO_EXCEPTIONS
++
++ template<class Function, class ResultType>
++ class FailureHandler
++ {
++ public:
++ template<typename F = Function>
++ static void create(F &&function, QFuture<ResultType> *future,
++ const QFutureInterface<ResultType> &fi);
++
++ template<typename F = Function>
++ static void create(F &&function, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi,
++ QObject *context);
++
++ template<typename F = Function>
++ FailureHandler(F &&func, const QFuture<ResultType> &f, QPromise<ResultType> &&p)
++ : promise(std::move(p)), parentFuture(f), handler(std::forward<F>(func))
++ {
++ }
++
++ public:
++ void run();
++
++ private:
++ template<class ArgType>
++ void handleException();
++ void handleAllExceptions();
++
++ private:
++ QPromise<ResultType> promise;
++ QFuture<ResultType> parentFuture;
++ Function handler;
++ };
++
++ #endif
++
++ template<typename Function, typename ResultType, typename ParentResultType>
++ void CompactContinuation<Function, ResultType, ParentResultType>::runFunction()
++ {
++ promise.start();
++
++ Q_ASSERT(parentFuture.isFinished());
++
++ #ifndef QT_NO_EXCEPTIONS
++ try {
++ #endif
++ if constexpr (!std::is_void_v<ResultType>) {
++ if constexpr (std::is_void_v<ParentResultType>) {
++ fulfillPromiseWithVoidResult();
++ } else if constexpr (std::is_invocable_v<Function, ParentResultType>) {
++ fulfillPromiseWithResult();
++ } else {
++ // This assert normally should never fail, this is to make sure
++ // that nothing unexpected happened.
++ static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
++ "The continuation is not invocable with the provided arguments");
++ fulfillPromise(parentFuture);
++ }
++ } else {
++ if constexpr (std::is_void_v<ParentResultType>) {
++ if constexpr (std::is_invocable_v<Function, QFuture<void>>)
++ this->object()(parentFuture);
++ else
++ this->object()();
++ } else if constexpr (std::is_invocable_v<Function, ParentResultType>) {
++ fulfillVoidPromise();
++ } else {
++ // This assert normally should never fail, this is to make sure
++ // that nothing unexpected happened.
++ static_assert(std::is_invocable_v<Function, QFuture<ParentResultType>>,
++ "The continuation is not invocable with the provided arguments");
++ this->object()(parentFuture);
++ }
++ }
++ #ifndef QT_NO_EXCEPTIONS
++ } catch (...) {
++ promise.setException(std::current_exception());
++ }
++ #endif
++ promise.finish();
++ }
++
++ template<typename Function, typename ResultType, typename ParentResultType>
++ bool CompactContinuation<Function, ResultType, ParentResultType>::execute()
++ {
++ Q_ASSERT(parentFuture.isFinished());
++
++ if (parentFuture.d.isChainCanceled()) {
++ #ifndef QT_NO_EXCEPTIONS
++ if (parentFuture.d.hasException()) {
++ // If the continuation doesn't take a QFuture argument, propagate the exception
++ // to the caller, by reporting it. If the continuation takes a QFuture argument,
++ // the user may want to catch the exception inside the continuation, to not
++ // interrupt the continuation chain, so don't report anything yet.
++ if constexpr (!std::is_invocable_v<std::decay_t<Function>, QFuture<ParentResultType>>) {
++ promise.start();
++ promise.setException(parentFuture.d.exceptionStore().exception());
++ promise.finish();
++ return false;
++ }
++ } else
++ #endif
++ {
++ promise.start();
++ promise.future().cancel();
++ promise.finish();
++ return false;
++ }
++ }
++
++ runImpl();
++ return true;
++ }
++
++ // Workaround for keeping move-only lambdas inside std::function
++ template<class Function>
++ struct ContinuationWrapper
++ {
++ ContinuationWrapper(Function &&f) : function(std::move(f)) { }
++ ContinuationWrapper(const ContinuationWrapper &other)
++ : function(std::move(const_cast<ContinuationWrapper &>(other).function))
++ {
++ Q_ASSERT_X(false, "QFuture", "Continuation shouldn't be copied");
++ }
++ ContinuationWrapper(ContinuationWrapper &&other) = default;
++ ContinuationWrapper &operator=(ContinuationWrapper &&) = default;
++
++ template <typename F = Function,
++ std::enable_if_t<std::is_invocable_v<F, const QFutureInterfaceBase &>, bool> = true>
++ void operator()(const QFutureInterfaceBase &parentData) { function(parentData); }
++
++ template <typename F = Function, std::enable_if_t<std::is_invocable_v<F>, bool> = true>
++ void operator()() { function(); }
++
++ private:
++ Function function;
++ };
++
++ template<typename Function, typename ResultType, typename ParentResultType>
++ template<typename F>
++ void CompactContinuation<Function, ResultType, ParentResultType>::create(F &&func,
++ QFuture<ParentResultType> *f,
++ QFutureInterface<ResultType> &fi,
++ QtFuture::Launch policy)
++ {
++ Q_ASSERT(f);
++
++ QThreadPool *pool = nullptr;
++
++ bool launchAsync = (policy == QtFuture::Launch::Async);
++ if (policy == QtFuture::Launch::Inherit) {
++ launchAsync = f->d.launchAsync();
++
++ // If the parent future was using a custom thread pool, inherit it as well.
++ if (launchAsync && f->d.threadPool()) {
++ pool = f->d.threadPool();
++ fi.setThreadPool(pool);
++ }
++ }
++
++ fi.setLaunchAsync(launchAsync);
++
++ auto continuation = [func = std::forward<F>(func), fi, promise_ = QPromise(fi), pool,
++ launchAsync](const QFutureInterfaceBase &parentData) mutable {
++ const auto parent = QFutureInterface<ParentResultType>(parentData).future();
++ CompactContinuation<Function, ResultType, ParentResultType> *continuationJob = nullptr;
++ if (launchAsync) {
++ auto asyncJob = new CompactContinuation<Function, ResultType, ParentResultType>(
++ std::forward<Function>(func), parent, std::move(promise_), pool);
++ fi.setRunnable(asyncJob->runnable());
++ continuationJob = asyncJob;
++ } else {
++ continuationJob = new CompactContinuation<Function, ResultType, ParentResultType>(
++ std::forward<Function>(func), parent, std::move(promise_));
++ }
++
++ bool isLaunched = continuationJob->execute();
++ // If continuation is successfully launched, AsyncContinuation will be deleted
++ // from the QRunnable's lambda. Synchronous continuation will be
++ // executed immediately, so it's safe to always delete it here.
++ if (!(launchAsync && isLaunched)) {
++ delete continuationJob;
++ continuationJob = nullptr;
++ }
++ };
++ f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d,
++ QFutureInterfaceBase::ContinuationType::Then);
++ }
++
++ template<typename Function, typename ResultType, typename ParentResultType>
++ template<typename F>
++ void CompactContinuation<Function, ResultType, ParentResultType>::create(F &&func,
++ QFuture<ParentResultType> *f,
++ QFutureInterface<ResultType> &fi,
++ QThreadPool *pool)
++ {
++ Q_ASSERT(f);
++
++ fi.setLaunchAsync(true);
++ fi.setThreadPool(pool);
++
++ auto continuation = [func = std::forward<F>(func), promise_ = QPromise(fi),
++ pool](const QFutureInterfaceBase &parentData) mutable {
++ const auto parent = QFutureInterface<ParentResultType>(parentData).future();
++ auto continuationJob = new CompactContinuation<Function, ResultType, ParentResultType>(
++ std::forward<Function>(func), parent, std::move(promise_), pool);
++ bool isLaunched = continuationJob->execute();
++ // If continuation is successfully launched, AsyncContinuation will be deleted
++ // from the QRunnable's lambda.
++ if (!isLaunched) {
++ delete continuationJob;
++ continuationJob = nullptr;
++ }
++ };
++ f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d,
++ QFutureInterfaceBase::ContinuationType::Then);
++ }
++
++ template<typename Function, typename ResultType, typename ParentResultType>
++ template<typename F>
++ void CompactContinuation<Function, ResultType, ParentResultType>::create(F &&func,
++ QFuture<ParentResultType> *f,
++ QFutureInterface<ResultType> &fi,
++ QObject *context)
++ {
++ Q_ASSERT(f);
++ Q_ASSERT(context);
++
++ // When the context object is destroyed, the signal-slot connection is broken and the
++ // continuation callback is destroyed. The promise that is created in the capture list is
++ // destroyed and, if it is not yet finished, cancelled.
++ auto continuation = [func = std::forward<F>(func), parent = *f,
++ promise_ = QPromise(fi)]() mutable {
++ CompactContinuation<Function, ResultType, ParentResultType> continuationJob(
++ std::forward<Function>(func), parent, std::move(promise_));
++ continuationJob.execute();
++ };
++
++ f->d.setContinuation(context, ContinuationWrapper(std::move(continuation)),
++ QVariant::fromValue(fi),
++ QFutureInterfaceBase::ContinuationType::Then);
++ }
++
++ template<typename Function, typename ResultType, typename ParentResultType>
++ void CompactContinuation<Function, ResultType, ParentResultType>::fulfillPromiseWithResult()
++ {
++ qfutureWarnIfUnusedResults(parentFuture.resultCount());
++ if constexpr (std::is_copy_constructible_v<ParentResultType>)
++ fulfillPromise(parentFuture.result());
++ else
++ fulfillPromise(parentFuture.takeResult());
++ }
++
++ template<typename Function, typename ResultType, typename ParentResultType>
++ void CompactContinuation<Function, ResultType, ParentResultType>::fulfillVoidPromise()
++ {
++ qfutureWarnIfUnusedResults(parentFuture.resultCount());
++ if constexpr (std::is_copy_constructible_v<ParentResultType>)
++ this->object()(parentFuture.result());
++ else
++ this->object()(parentFuture.takeResult());
++ }
++
++ template<typename Function, typename ResultType, typename ParentResultType>
++ void CompactContinuation<Function, ResultType, ParentResultType>::fulfillPromiseWithVoidResult()
++ {
++ if constexpr (std::is_invocable_v<Function, QFuture<void>>)
++ fulfillPromise(parentFuture);
++ else
++ fulfillPromise();
++ }
++
++ template<typename Function, typename ResultType, typename ParentResultType>
++ template<class... Args>
++ void CompactContinuation<Function, ResultType, ParentResultType>::fulfillPromise(Args &&... args)
++ {
++ promise.addResult(std::invoke(this->object(), std::forward<Args>(args)...));
++ }
++
++ template<class T>
++ void fulfillPromise(QPromise<T> &promise, QFuture<T> &future)
++ {
++ if constexpr (!std::is_void_v<T>) {
++ if constexpr (std::is_copy_constructible_v<T>)
++ promise.addResult(future.result());
++ else
++ promise.addResult(future.takeResult());
++ }
++ }
++
++ template<class T, class Function>
++ void fulfillPromise(QPromise<T> &promise, Function &&handler)
++ {
++ if constexpr (std::is_void_v<T>)
++ handler();
++ else
++ promise.addResult(handler());
++ }
++
++ #ifndef QT_NO_EXCEPTIONS
++
++ template<class Function, class ResultType>
++ template<class F>
++ void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultType> *future,
++ const QFutureInterface<ResultType> &fi)
++ {
++ Q_ASSERT(future);
++
++ auto failureContinuation = [function = std::forward<F>(function), promise_ = QPromise(fi)](
++ const QFutureInterfaceBase &parentData) mutable {
++ const auto parent = QFutureInterface<ResultType>(parentData).future();
++ FailureHandler<Function, ResultType> failureHandler(std::forward<Function>(function),
++ parent, std::move(promise_));
++ failureHandler.run();
++ };
++
++ future->d.setContinuation(ContinuationWrapper(std::move(failureContinuation)), fi.d,
++ QFutureInterfaceBase::ContinuationType::OnFailed);
++ }
++
++ template<class Function, class ResultType>
++ template<class F>
++ void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultType> *future,
++ QFutureInterface<ResultType> &fi,
++ QObject *context)
++ {
++ Q_ASSERT(future);
++ Q_ASSERT(context);
++ auto failureContinuation = [function = std::forward<F>(function),
++ parent = *future, promise_ = QPromise(fi)]() mutable {
++ FailureHandler<Function, ResultType> failureHandler(
++ std::forward<Function>(function), parent, std::move(promise_));
++ failureHandler.run();
++ };
++
++ future->d.setContinuation(context, ContinuationWrapper(std::move(failureContinuation)),
++ QVariant::fromValue(fi),
++ QFutureInterfaceBase::ContinuationType::OnFailed);
++ }
++
++ template<class Function, class ResultType>
++ void FailureHandler<Function, ResultType>::run()
++ {
++ Q_ASSERT(parentFuture.isFinished());
++
++ promise.start();
++
++ if (parentFuture.d.hasException()) {
++ using ArgType = typename QtPrivate::ArgResolver<Function>::First;
++ if constexpr (std::is_void_v<ArgType>) {
++ handleAllExceptions();
++ } else {
++ handleException<ArgType>();
++ }
++ } else if (parentFuture.d.isChainCanceled()) {
++ promise.future().cancel();
++ } else {
++ QtPrivate::fulfillPromise(promise, parentFuture);
++ }
++ promise.finish();
++ }
++
++ template<class Function, class ResultType>
++ template<class ArgType>
++ void FailureHandler<Function, ResultType>::handleException()
++ {
++ try {
++ Q_ASSERT(parentFuture.d.hasException());
++ parentFuture.d.exceptionStore().rethrowException();
++ } catch (const ArgType &e) {
++ try {
++ // Handle exceptions matching with the handler's argument type
++ if constexpr (std::is_void_v<ResultType>)
++ handler(e);
++ else
++ promise.addResult(handler(e));
++ } catch (...) {
++ promise.setException(std::current_exception());
++ }
++ } catch (...) {
++ // Exception doesn't match with handler's argument type, propagate
++ // the exception to be handled later.
++ promise.setException(std::current_exception());
++ }
++ }
++
++ template<class Function, class ResultType>
++ void FailureHandler<Function, ResultType>::handleAllExceptions()
++ {
++ try {
++ Q_ASSERT(parentFuture.d.hasException());
++ parentFuture.d.exceptionStore().rethrowException();
++ } catch (...) {
++ try {
++ QtPrivate::fulfillPromise(promise, std::forward<Function>(handler));
++ } catch (...) {
++ promise.setException(std::current_exception());
++ }
++ }
++ }
++
++ #endif // QT_NO_EXCEPTIONS
++
++ template<class Function, class ResultType>
++ class CanceledHandler
++ {
++ public:
++ template<class F = Function>
++ static void create(F &&handler, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi)
++ {
++ Q_ASSERT(future);
++
++ auto canceledContinuation = [promise = QPromise(fi), handler = std::forward<F>(handler)](
++ const QFutureInterfaceBase &parentData) mutable {
++ auto parentFuture = QFutureInterface<ResultType>(parentData).future();
++ run(std::forward<F>(handler), parentFuture, std::move(promise));
++ };
++ future->d.setContinuation(ContinuationWrapper(std::move(canceledContinuation)), fi.d,
++ QFutureInterfaceBase::ContinuationType::OnCanceled);
++ }
++
++ template<class F = Function>
++ static void create(F &&handler, QFuture<ResultType> *future, QFutureInterface<ResultType> &fi,
++ QObject *context)
++ {
++ Q_ASSERT(future);
++ Q_ASSERT(context);
++ auto canceledContinuation = [handler = std::forward<F>(handler),
++ parentFuture = *future, promise = QPromise(fi)]() mutable {
++ run(std::forward<F>(handler), parentFuture, std::move(promise));
++ };
++
++ future->d.setContinuation(context, ContinuationWrapper(std::move(canceledContinuation)),
++ QVariant::fromValue(fi),
++ QFutureInterfaceBase::ContinuationType::OnCanceled);
++ }
++
++ template<class F = Function>
++ static void run(F &&handler, QFuture<ResultType> &parentFuture, QPromise<ResultType> &&promise)
++ {
++ promise.start();
++
++ if (parentFuture.isCanceled()) {
++ #ifndef QT_NO_EXCEPTIONS
++ if (parentFuture.d.hasException()) {
++ // Propagate the exception to the result future
++ promise.setException(parentFuture.d.exceptionStore().exception());
++ } else {
++ try {
++ #endif
++ QtPrivate::fulfillPromise(promise, std::forward<F>(handler));
++ #ifndef QT_NO_EXCEPTIONS
++ } catch (...) {
++ promise.setException(std::current_exception());
++ }
++ }
++ #endif
++ } else {
++ QtPrivate::fulfillPromise(promise, parentFuture);
++ }
++
++ promise.finish();
++ }
++ };
++
++ struct UnwrapHandler
++ {
++ template<class T>
++ static auto unwrapImpl(T *outer)
++ {
++ Q_ASSERT(outer);
++
++ using ResultType = typename QtPrivate::Future<std::decay_t<T>>::type;
++ using NestedType = typename QtPrivate::Future<ResultType>::type;
++ QFutureInterface<NestedType> promise(QFutureInterfaceBase::State::Pending);
++
++ auto outerPromise = QFutureInterfaceBase::get(*outer);
++ outerPromise.setAddResultsIfCanceledEnabled(true);
++
++ outerPromise.setContinuation([promise](const QFutureInterfaceBase &outerFutureBase) mutable {
++ QFutureInterface<ResultType> outerFuture(outerFutureBase);
++ promise.reportStarted();
++
++ Q_ASSERT(outerFuture.isFinished());
++
++ #ifndef QT_NO_EXCEPTIONS
++ if (outerFuture.hasException()) {
++ promise.reportException(outerFuture.exceptionStore().exception());
++ promise.reportFinished();
++ return;
++ }
++ #endif
++ if (outerFuture.isCanceled())
++ promise.reportCanceled();
++
++ if (outerFuture.resultCount() == 0) {
++ promise.reportFinished();
++ return;
++ }
++
++ auto nestedFuture = QFutureInterfaceBase::get(outerFuture.resultReference(0));
++
++ if (outerFuture.isCanceled())
++ nestedFuture.cancelChain();
++
++ nestedFuture.setContinuation([promise](const QFutureInterfaceBase &nestedFutureBase) mutable {
++ QFutureInterface<NestedType> nested(nestedFutureBase);
++ #ifndef QT_NO_EXCEPTIONS
++ if (nested.hasException()) {
++ promise.reportException(nested.exceptionStore().exception());
++ promise.reportFinished();
++ return;
++ }
++ #endif
++ if (nested.isCanceled())
++ promise.reportCanceled();
++
++ if constexpr (!std::is_void_v<NestedType>)
++ promise.reportResults(nested.results());
++
++ promise.reportFinished();
++ }, promise.d, QFutureInterfaceBase::ContinuationType::Then);
++ }, promise.d, QFutureInterfaceBase::ContinuationType::Then);
++
++ return promise.future();
++ }
++ };
++
++ template<typename ValueType>
++ QFuture<ValueType> makeReadyRangeFutureImpl(const QList<ValueType> &values)
++ {
++ QFutureInterface<ValueType> promise;
++ promise.reportStarted();
++ promise.reportResults(values);
++ promise.reportFinished();
++ return promise.future();
++ }
++
++ } // namespace QtPrivate
++
++ namespace QtFuture {
++
++ template<class Signal>
++ using ArgsType = typename QtPrivate::ArgResolver<Signal>::AllArgs;
++
++ template<class Sender, class Signal, typename = QtPrivate::EnableIfInvocable<Sender, Signal>>
++ static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
++ {
++ using ArgsType = ArgsType<Signal>;
++ QFutureInterface<ArgsType> promise;
++ promise.reportStarted();
++ if (!sender) {
++ promise.reportCanceled();
++ promise.reportFinished();
++ return promise.future();
++ }
++
++ using Connections = std::pair<QMetaObject::Connection, QMetaObject::Connection>;
++ auto connections = std::make_shared<Connections>();
++
++ if constexpr (std::is_void_v<ArgsType>) {
++ connections->first =
++ QObject::connect(sender, signal, sender, [promise, connections]() mutable {
++ QObject::disconnect(connections->first);
++ QObject::disconnect(connections->second);
++ promise.reportFinished();
++ });
++ } else if constexpr (QtPrivate::ArgResolver<Signal>::HasExtraArgs) {
++ connections->first = QObject::connect(sender, signal, sender,
++ [promise, connections](auto... values) mutable {
++ QObject::disconnect(connections->first);
++ QObject::disconnect(connections->second);
++ promise.reportResult(QtPrivate::createTuple(
++ std::move(values)...));
++ promise.reportFinished();
++ });
++ } else {
++ connections->first = QObject::connect(sender, signal, sender,
++ [promise, connections](ArgsType value) mutable {
++ QObject::disconnect(connections->first);
++ QObject::disconnect(connections->second);
++ promise.reportResult(value);
++ promise.reportFinished();
++ });
++ }
++
++ if (!connections->first) {
++ promise.reportCanceled();
++ promise.reportFinished();
++ return promise.future();
++ }
++
++ connections->second =
++ QObject::connect(sender, &QObject::destroyed, sender, [promise, connections]() mutable {
++ QObject::disconnect(connections->first);
++ QObject::disconnect(connections->second);
++ promise.reportCanceled();
++ promise.reportFinished();
++ });
++
++ return promise.future();
++ }
++
++ template<typename Container>
++ using if_container_with_input_iterators =
++ std::enable_if_t<QtPrivate::HasInputIterator<Container>::value, bool>;
++
++ template<typename Container>
++ using ContainedType =
++ typename std::iterator_traits<decltype(
++ std::cbegin(std::declval<Container&>()))>::value_type;
++
++ template<typename Container, if_container_with_input_iterators<Container> = true>
++ static QFuture<ContainedType<Container>> makeReadyRangeFuture(Container &&container)
++ {
++ // handle QList<T> separately, because reportResults() takes a QList
++ // as an input
++ using ValueType = ContainedType<Container>;
++ if constexpr (std::is_convertible_v<q20::remove_cvref_t<Container>, QList<ValueType>>) {
++ return QtPrivate::makeReadyRangeFutureImpl(container);
++ } else {
++ return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{std::cbegin(container),
++ std::cend(container)});
++ }
++ }
++
++ template<typename ValueType>
++ static QFuture<ValueType> makeReadyRangeFuture(std::initializer_list<ValueType> values)
++ {
++ return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{values});
++ }
++
++ template<typename T>
++ static QFuture<std::decay_t<T>> makeReadyValueFuture(T &&value)
++ {
++ QFutureInterface<std::decay_t<T>> promise;
++ promise.reportStarted();
++ promise.reportResult(std::forward<T>(value));
++ promise.reportFinished();
++
++ return promise.future();
++ }
++
++ Q_CORE_EXPORT QFuture<void> makeReadyVoidFuture(); // implemented in qfutureinterface.cpp
++
++ #if QT_DEPRECATED_SINCE(6, 10)
++ template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
++ QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyValueFuture() instead.")
++ static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
++ {
++ return makeReadyValueFuture(std::forward<T>(value));
++ }
++
++ // the void specialization is moved to the end of qfuture.h, because it now
++ // uses makeReadyVoidFuture() and required QFuture<void> to be defined.
++
++ template<typename T>
++ QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyRangeFuture() instead.")
++ static QFuture<T> makeReadyFuture(const QList<T> &values)
++ {
++ return makeReadyRangeFuture(values);
++ }
++ #endif // QT_DEPRECATED_SINCE(6, 10)
++
++ #ifndef QT_NO_EXCEPTIONS
++
++ template<typename T = void>
++ static QFuture<T> makeExceptionalFuture(std::exception_ptr exception)
++ {
++ QFutureInterface<T> promise;
++ promise.reportStarted();
++ promise.reportException(exception);
++ promise.reportFinished();
++
++ return promise.future();
++ }
++
++ template<typename T = void>
++ static QFuture<T> makeExceptionalFuture(const QException &exception)
++ {
++ try {
++ exception.raise();
++ } catch (...) {
++ return makeExceptionalFuture<T>(std::current_exception());
++ }
++ Q_UNREACHABLE();
++ }
++
++ #endif // QT_NO_EXCEPTIONS
++
++ } // namespace QtFuture
++
++ namespace QtPrivate {
++
++ template<typename ResultFutures>
++ struct WhenAllContext
++ {
++ using ValueType = typename ResultFutures::value_type;
++
++ explicit WhenAllContext(qsizetype size) : remaining(size) {}
++
++ template<typename T = ValueType>
++ void checkForCompletion(qsizetype index, T &&future)
++ {
++ futures[index] = std::forward<T>(future);
++ const auto oldRemaining = remaining.fetchAndSubRelaxed(1);
++ Q_ASSERT(oldRemaining > 0);
++ if (oldRemaining <= 1) { // that was the last one
++ promise.addResult(futures);
++ promise.finish();
++ }
++ }
++
++ QAtomicInteger<qsizetype> remaining;
++ QPromise<ResultFutures> promise;
++ ResultFutures futures;
++ };
++
++ template<typename ResultType>
++ struct WhenAnyContext
++ {
++ using ValueType = ResultType;
++
++ template<typename T = ResultType, typename = EnableForNonVoid<T>>
++ void checkForCompletion(qsizetype, T &&result)
++ {
++ if (!ready.fetchAndStoreRelaxed(true)) {
++ promise.addResult(std::forward<T>(result));
++ promise.finish();
++ }
++ }
++
++ QAtomicInt ready = false;
++ QPromise<ResultType> promise;
++ };
++
++ template<qsizetype Index, typename ContextType, typename... Ts>
++ void addCompletionHandlersImpl(const std::shared_ptr<ContextType> &context,
++ const std::tuple<Ts...> &t)
++ {
++ auto future = std::get<Index>(t);
++ using ResultType = typename ContextType::ValueType;
++ // Need context=context so that the compiler does not infer the captured variable's type as 'const'
++ future.then([context=context](const std::tuple_element_t<Index, std::tuple<Ts...>> &f) {
++ context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, f });
++ }).onCanceled([context=context, future]() {
++ context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, future });
++ });
++
++ if constexpr (Index != 0)
++ addCompletionHandlersImpl<Index - 1, ContextType, Ts...>(context, t);
++ }
++
++ template<typename ContextType, typename... Ts>
++ void addCompletionHandlers(const std::shared_ptr<ContextType> &context, const std::tuple<Ts...> &t)
++ {
++ constexpr qsizetype size = std::tuple_size<std::tuple<Ts...>>::value;
++ addCompletionHandlersImpl<size - 1, ContextType, Ts...>(context, t);
++ }
++
++ template<typename OutputSequence, typename InputIt, typename ValueType,
++ std::enable_if_t<std::conjunction_v<IsForwardIterable<InputIt>, isQFuture<ValueType>>,
++ bool> = true>
++ QFuture<OutputSequence> whenAllImpl(InputIt first, InputIt last)
++ {
++ const qsizetype size = std::distance(first, last);
++ if (size == 0)
++ return QtFuture::makeReadyValueFuture(OutputSequence());
++
++ const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
++ context->futures.resize(size);
++ context->promise.start();
++
++ qsizetype idx = 0;
++ for (auto it = first; it != last; ++it, ++idx) {
++ // Need context=context so that the compiler does not infer the captured variable's type as 'const'
++ it->then([context=context, idx](const ValueType &f) {
++ context->checkForCompletion(idx, f);
++ }).onCanceled([context=context, idx, f = *it] {
++ context->checkForCompletion(idx, f);
++ });
++ }
++ return context->promise.future();
++ }
++
++ template<typename OutputSequence, typename... Futures>
++ QFuture<OutputSequence> whenAllImpl(Futures &&... futures)
++ {
++ constexpr qsizetype size = sizeof...(Futures);
++ const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
++ context->futures.resize(size);
++ context->promise.start();
++
++ QtPrivate::addCompletionHandlers(context, std::make_tuple(std::forward<Futures>(futures)...));
++
++ return context->promise.future();
++ }
++
++ template<typename InputIt, typename ValueType,
++ std::enable_if_t<std::conjunction_v<IsForwardIterable<InputIt>, isQFuture<ValueType>>,
++ bool> = true>
++ QFuture<QtFuture::WhenAnyResult<typename Future<ValueType>::type>> whenAnyImpl(InputIt first,
++ InputIt last)
++ {
++ using PackagedType = typename Future<ValueType>::type;
++ using ResultType = QtFuture::WhenAnyResult<PackagedType>;
++
++ const qsizetype size = std::distance(first, last);
++ if (size == 0) {
++ return QtFuture::makeReadyValueFuture(
++ QtFuture::WhenAnyResult { qsizetype(-1), QFuture<PackagedType>() });
++ }
++
++ const auto context = std::make_shared<QtPrivate::WhenAnyContext<ResultType>>();
++ context->promise.start();
++
++ qsizetype idx = 0;
++ for (auto it = first; it != last; ++it, ++idx) {
++ // Need context=context so that the compiler does not infer the captured variable's type as 'const'
++ it->then([context=context, idx](const ValueType &f) {
++ context->checkForCompletion(idx, QtFuture::WhenAnyResult { idx, f });
++ }).onCanceled([context=context, idx, f = *it] {
++ context->checkForCompletion(idx, QtFuture::WhenAnyResult { idx, f });
++ });
++ }
++ return context->promise.future();
++ }
++
++ template<typename... Futures>
++ QFuture<std::variant<std::decay_t<Futures>...>> whenAnyImpl(Futures &&... futures)
++ {
++ using ResultType = std::variant<std::decay_t<Futures>...>;
++
++ const auto context = std::make_shared<QtPrivate::WhenAnyContext<ResultType>>();
++ context->promise.start();
++
++ QtPrivate::addCompletionHandlers(context, std::make_tuple(std::forward<Futures>(futures)...));
++
++ return context->promise.future();
++ }
++
++ } // namespace QtPrivate
++
++ QT_END_NAMESPACE