summaryrefslogtreecommitdiffstats
path: root/src/concurrent
diff options
context:
space:
mode:
authorJarek Kobus <jaroslaw.kobus@qt.io>2020-07-26 14:05:24 +0200
committerJarek Kobus <jaroslaw.kobus@qt.io>2020-08-19 12:46:10 +0200
commit765f503b1e0b3ab18b1847fb2d91aa3e9da94ecb (patch)
tree036099821a3b09f7d39e3824a04a7555b696fbdf /src/concurrent
parent0243951e0aba20a010577f09d6486f21d621d575 (diff)
QtConcurrent: Introduce runWithPromise()
The differences to run() method: 1. The passed function should have additional argument QPromise<T> &, declared as a first argument. 2. The return value of the function must be void. Result reporting should be done through passed QPromise<T> &promise argument. 3. By default, runWithPromise() doesn't support functors with overloaded operator()(). In case of overloaded functors the user needs to explicitly specify the result type as a template parameter passed to runWithPromise, like: struct Functor { void operator()(QPromise<int> &) { } void operator()(QPromise<double> &) { } }; Functor f; runWithPromise<double>(f); // this will select the 2nd overload Task-number: QTBUG-84702 Change-Id: Ie40d466938d316fc46eb7690e6ae0ce1c6c6d649 Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
Diffstat (limited to 'src/concurrent')
-rw-r--r--src/concurrent/qtconcurrentrun.h139
-rw-r--r--src/concurrent/qtconcurrentstoredfunctioncall.h89
2 files changed, 226 insertions, 2 deletions
diff --git a/src/concurrent/qtconcurrentrun.h b/src/concurrent/qtconcurrentrun.h
index 4f583a343c..2f9b1b5e96 100644
--- a/src/concurrent/qtconcurrentrun.h
+++ b/src/concurrent/qtconcurrentrun.h
@@ -67,13 +67,108 @@ namespace QtConcurrent {
namespace QtConcurrent {
+// Note: It's a copy taken from qfuture_impl.h with some specialization added
+// TODO: Get rid of the code repetition and unify this for both purposes, see QTBUG-83331
+template<typename...>
+struct ArgsType;
+
+template<typename Arg, typename... Args>
+struct ArgsType<Arg, Args...>
+{
+ using PromiseType = void;
+ static const bool IsPromise = false;
+};
+
+// Note: this specialization was added
+template<typename Arg, typename... Args>
+struct ArgsType<QPromise<Arg> &, Args...>
+{
+ using PromiseType = Arg;
+ static const bool IsPromise = true;
+};
+
+template<>
+struct ArgsType<>
+{
+ using PromiseType = void;
+ static const bool IsPromise = false;
+};
+
+template<typename F>
+struct ArgResolver : ArgResolver<decltype(&std::decay_t<F>::operator())>
+{
+};
+
+// Note: this specialization was added, see callableObjectWithState() test in qtconcurrentrun
+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...>
+{
+};
+
+// Note: this specialization was added, see light() test in qtconcurrentrun
+template<typename R, typename... Args>
+struct ArgResolver<R (*&)(Args...)> : public ArgsType<Args...>
+{
+};
+
+// Note: this specialization was added, see light() test in qtconcurrentrun
+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...>
+{
+};
+
+// Note: this specialization was added, see crefFunction() test in qtconcurrentrun
+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 Function, class ...Args>
[[nodiscard]]
auto run(QThreadPool *pool, Function &&f, Args &&...args)
{
return (new StoredFunctionCall<Function, Args...>(
- std::forward<Function>(f), std::forward<Args>(args)...))
- ->start(pool);
+ std::forward<Function>(f), std::forward<Args>(args)...))->start(pool);
}
template <class Function, class ...Args>
@@ -83,6 +178,46 @@ auto run(Function &&f, Args &&...args)
return run(QThreadPool::globalInstance(), std::forward<Function>(f), std::forward<Args>(args)...);
}
+template <class PromiseType, class Function, class ...Args>
+[[nodiscard]]
+auto runWithPromise(QThreadPool *pool, Function &&f, Args &&...args)
+{
+ return (new StoredFunctionCallWithPromise<Function, PromiseType, Args...>(
+ std::forward<Function>(f), std::forward<Args>(args)...))->start(pool);
+}
+
+template <class Function, class ...Args>
+[[nodiscard]]
+auto runWithPromise(QThreadPool *pool, Function &&f, Args &&...args)
+{
+ static_assert(ArgResolver<Function>::IsPromise, "The first argument of passed callable object isn't a QPromise<T> & type.");
+ using PromiseType = typename ArgResolver<Function>::PromiseType;
+ return runWithPromise<PromiseType>(pool, std::forward<Function>(f), std::forward<Args>(args)...);
+}
+
+template <class Function, class ...Args>
+[[nodiscard]]
+auto runWithPromise(QThreadPool *pool, std::reference_wrapper<const Function> &&functionWrapper, Args &&...args)
+{
+ static_assert(ArgResolver<const Function>::IsPromise, "The first argument of passed callable object isn't a QPromise<T> & type.");
+ using PromiseType = typename ArgResolver<const Function>::PromiseType;
+ return runWithPromise<PromiseType>(pool, std::forward<const Function>(functionWrapper.get()), std::forward<Args>(args)...);
+}
+
+template <class PromiseType, class Function, class ...Args>
+[[nodiscard]]
+auto runWithPromise(Function &&f, Args &&...args)
+{
+ return runWithPromise<PromiseType>(QThreadPool::globalInstance(), std::forward<Function>(f), std::forward<Args>(args)...);
+}
+
+template <class Function, class ...Args>
+[[nodiscard]]
+auto runWithPromise(Function &&f, Args &&...args)
+{
+ return runWithPromise(QThreadPool::globalInstance(), std::forward<Function>(f), std::forward<Args>(args)...);
+}
+
} //namespace QtConcurrent
#endif // Q_CLANG_QDOC
diff --git a/src/concurrent/qtconcurrentstoredfunctioncall.h b/src/concurrent/qtconcurrentstoredfunctioncall.h
index f6d47f5119..a15f254c1e 100644
--- a/src/concurrent/qtconcurrentstoredfunctioncall.h
+++ b/src/concurrent/qtconcurrentstoredfunctioncall.h
@@ -46,12 +46,76 @@
#include <QtConcurrent/qtconcurrentrunbase.h>
#include <type_traits>
+#include <qpromise.h>
+
QT_BEGIN_NAMESPACE
#ifndef Q_QDOC
namespace QtConcurrent {
+template<typename...>
+struct NonMemberFunctionResolver;
+
+template <class Function, class PromiseType, class... Args>
+struct NonMemberFunctionResolver<Function, PromiseType, Args...>
+{
+ using Type = std::tuple<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>;
+ static_assert(std::is_invocable_v<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>,
+ "It's not possible to invoke the function with passed arguments.");
+ static_assert(std::is_void_v<std::invoke_result_t<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>>,
+ "The function must return void type.");
+
+ static constexpr decltype (auto) invokePointer()
+ {
+ return &std::invoke<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>;
+ }
+ static Type initData(Function &&f, QPromise<PromiseType> &promise, Args &&...args)
+ {
+ return Type { std::forward<Function>(f), std::ref(promise), std::forward<Args>(args)... };
+ }
+};
+
+template<typename...>
+struct MemberFunctionResolver;
+
+template <typename Function, typename PromiseType, typename Arg, typename ... Args>
+struct MemberFunctionResolver<Function, PromiseType, Arg, Args...>
+{
+ using Type = std::tuple<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>;
+ static_assert(std::is_invocable_v<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>,
+ "It's not possible to invoke the function with passed arguments.");
+ static_assert(std::is_void_v<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>>,
+ "The function must return void type.");
+
+ static constexpr decltype (auto) invokePointer()
+ {
+ return &std::invoke<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>;
+ }
+ static Type initData(Function &&f, QPromise<PromiseType> &promise, Arg &&fa, Args &&...args)
+ {
+ return Type { std::forward<Function>(f), std::forward<Arg>(fa), std::ref(promise), std::forward<Args>(args)... };
+ }
+};
+
+template <class IsMember, class Function, class PromiseType, class... Args>
+struct FunctionResolverHelper;
+
+template <class Function, class PromiseType, class... Args>
+struct FunctionResolverHelper<std::false_type, Function, PromiseType, Args...> : public NonMemberFunctionResolver<Function, PromiseType, Args...>
+{
+};
+
+template <class Function, class PromiseType, class... Args>
+struct FunctionResolverHelper<std::true_type, Function, PromiseType, Args...> : public MemberFunctionResolver<Function, PromiseType, Args...>
+{
+};
+
+template <class Function, class PromiseType, class... Args>
+struct FunctionResolver : public FunctionResolverHelper<typename std::is_member_function_pointer<std::decay_t<Function>>::type, Function, PromiseType, Args...>
+{
+};
+
template <class Function, class ...Args>
struct InvokeResult
{
@@ -94,6 +158,31 @@ private:
DecayedTuple<Function, Args...> data;
};
+template <class Function, class PromiseType, class ...Args>
+struct StoredFunctionCallWithPromise : public RunFunctionTaskBase<PromiseType>
+{
+ using Resolver = FunctionResolver<Function, PromiseType, Args...>;
+ using DataType = typename Resolver::Type;
+ StoredFunctionCallWithPromise(Function &&f, Args &&...args)
+ : prom(this->promise),
+ data(std::move(Resolver::initData(std::forward<Function>(f), std::ref(prom), std::forward<Args>(args)...)))
+ {}
+
+ StoredFunctionCallWithPromise(DataType &&_data)
+ : data(std::move(_data))
+ {}
+
+protected:
+ void runFunctor() override
+ {
+ std::apply(Resolver::invokePointer(), std::move(data));
+ }
+
+private:
+ QPromise<PromiseType> prom;
+ DataType data;
+};
+
} //namespace QtConcurrent
#endif // Q_QDOC