diff options
author | Jarek Kobus <jaroslaw.kobus@qt.io> | 2020-07-26 14:05:24 +0200 |
---|---|---|
committer | Jarek Kobus <jaroslaw.kobus@qt.io> | 2020-08-19 12:46:10 +0200 |
commit | 765f503b1e0b3ab18b1847fb2d91aa3e9da94ecb (patch) | |
tree | 036099821a3b09f7d39e3824a04a7555b696fbdf /src/concurrent | |
parent | 0243951e0aba20a010577f09d6486f21d621d575 (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.h | 139 | ||||
-rw-r--r-- | src/concurrent/qtconcurrentstoredfunctioncall.h | 89 |
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 |