File indexing completed on 2025-02-21 10:09:51
0001
0002
0003
0004 #ifndef QTCONCURRENT_STOREDFUNCTIONCALL_H
0005 #define QTCONCURRENT_STOREDFUNCTIONCALL_H
0006
0007 #include <QtConcurrent/qtconcurrent_global.h>
0008
0009 #ifndef QT_NO_CONCURRENT
0010 #include <QtConcurrent/qtconcurrentrunbase.h>
0011 #include <QtCore/qpromise.h>
0012
0013 #include <type_traits>
0014
0015 QT_BEGIN_NAMESPACE
0016
0017 #ifndef Q_QDOC
0018
0019 namespace QtConcurrent {
0020
0021 template<typename...>
0022 struct NonMemberFunctionResolver;
0023
0024 template <class Function, class PromiseType, class... Args>
0025 struct NonMemberFunctionResolver<Function, PromiseType, Args...>
0026 {
0027 using Type = std::tuple<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>;
0028 static_assert(std::is_invocable_v<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>,
0029 "It's not possible to invoke the function with passed arguments.");
0030 static_assert(std::is_void_v<std::invoke_result_t<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>>,
0031 "The function must return void type.");
0032
0033 static constexpr void invoke(std::decay_t<Function> function, QPromise<PromiseType> &promise,
0034 std::decay_t<Args>... args)
0035 {
0036 std::invoke(function, promise, args...);
0037 }
0038 static Type initData(Function &&f, QPromise<PromiseType> &promise, Args &&...args)
0039 {
0040 return Type { std::forward<Function>(f), std::ref(promise), std::forward<Args>(args)... };
0041 }
0042 };
0043
0044 template<typename...>
0045 struct MemberFunctionResolver;
0046
0047 template <typename Function, typename PromiseType, typename Arg, typename ... Args>
0048 struct MemberFunctionResolver<Function, PromiseType, Arg, Args...>
0049 {
0050 using Type = std::tuple<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>;
0051 static_assert(std::is_invocable_v<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>,
0052 "It's not possible to invoke the function with passed arguments.");
0053 static_assert(std::is_void_v<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>>,
0054 "The function must return void type.");
0055
0056 static constexpr void invoke(std::decay_t<Function> function, std::decay_t<Arg> object,
0057 QPromise<PromiseType> &promise, std::decay_t<Args>... args)
0058 {
0059 std::invoke(function, object, promise, args...);
0060 }
0061 static Type initData(Function &&f, QPromise<PromiseType> &promise, Arg &&fa, Args &&...args)
0062 {
0063 return Type { std::forward<Function>(f), std::forward<Arg>(fa), std::ref(promise), std::forward<Args>(args)... };
0064 }
0065 };
0066
0067 template <class IsMember, class Function, class PromiseType, class... Args>
0068 struct FunctionResolverHelper;
0069
0070 template <class Function, class PromiseType, class... Args>
0071 struct FunctionResolverHelper<std::false_type, Function, PromiseType, Args...>
0072 : public NonMemberFunctionResolver<Function, PromiseType, Args...>
0073 {
0074 };
0075
0076 template <class Function, class PromiseType, class... Args>
0077 struct FunctionResolverHelper<std::true_type, Function, PromiseType, Args...>
0078 : public MemberFunctionResolver<Function, PromiseType, Args...>
0079 {
0080 };
0081
0082 template <class Function, class PromiseType, class... Args>
0083 struct FunctionResolver
0084 : public FunctionResolverHelper<typename std::is_member_function_pointer<
0085 std::decay_t<Function>>::type, Function, PromiseType, Args...>
0086 {
0087 };
0088
0089 template <class Function, class ...Args>
0090 struct InvokeResult
0091 {
0092 static_assert(std::is_invocable_v<std::decay_t<Function>, std::decay_t<Args>...>,
0093 "It's not possible to invoke the function with passed arguments.");
0094
0095 using Type = std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>;
0096 };
0097
0098 template <class Function, class ...Args>
0099 using InvokeResultType = typename InvokeResult<Function, Args...>::Type;
0100
0101 template <class ...Types>
0102 using DecayedTuple = std::tuple<std::decay_t<Types>...>;
0103
0104 template <class Function, class ...Args>
0105 struct StoredFunctionCall : public RunFunctionTaskBase<InvokeResultType<Function, Args...>>
0106 {
0107 StoredFunctionCall(DecayedTuple<Function, Args...> &&_data)
0108 : data(std::move(_data))
0109 {}
0110
0111 protected:
0112 void runFunctor() override
0113 {
0114 constexpr auto invoke = [] (std::decay_t<Function> function,
0115 std::decay_t<Args>... args) -> auto {
0116 return std::invoke(function, args...);
0117 };
0118
0119 if constexpr (std::is_void_v<InvokeResultType<Function, Args...>>) {
0120 std::apply(invoke, std::move(data));
0121 } else {
0122 auto result = std::apply(invoke, std::move(data));
0123
0124 using T = InvokeResultType<Function, Args...>;
0125 if constexpr (std::is_move_constructible_v<T>)
0126 this->promise.reportAndMoveResult(std::move(result));
0127 else if constexpr (std::is_copy_constructible_v<T>)
0128 this->promise.reportResult(result);
0129 }
0130 }
0131
0132 private:
0133 DecayedTuple<Function, Args...> data;
0134 };
0135
0136 template <class Function, class PromiseType, class ...Args>
0137 struct StoredFunctionCallWithPromise : public RunFunctionTaskBase<PromiseType>
0138 {
0139 using Resolver = FunctionResolver<Function, PromiseType, Args...>;
0140 using DataType = typename Resolver::Type;
0141 StoredFunctionCallWithPromise(Function &&f, Args &&...args)
0142 : prom(this->promise),
0143 data(std::move(Resolver::initData(std::forward<Function>(f), std::ref(prom),
0144 std::forward<Args>(args)...)))
0145 {}
0146
0147 StoredFunctionCallWithPromise(DecayedTuple<Function, Args...> &&_data)
0148 : StoredFunctionCallWithPromise(std::move(_data),
0149 std::index_sequence_for<std::decay_t<Function>, std::decay_t<Args>...>())
0150 {}
0151
0152 protected:
0153 void runFunctor() override
0154 {
0155 std::apply(Resolver::invoke, std::move(data));
0156 }
0157
0158 private:
0159
0160 template<std::size_t... Is>
0161 StoredFunctionCallWithPromise(DecayedTuple<Function, Args...> &&_data,
0162 std::index_sequence<Is...>)
0163 : StoredFunctionCallWithPromise(std::move(std::get<Is>(_data))...)
0164 {}
0165
0166 QPromise<PromiseType> prom;
0167 DataType data;
0168 };
0169
0170 template<typename...>
0171 struct NonPromiseTaskResolver;
0172
0173 template <typename Function, typename ... Args>
0174 struct NonPromiseTaskResolver<Function, Args...>
0175 {
0176 using TaskWithArgs = DecayedTuple<Function, Args...>;
0177 static auto run(TaskWithArgs &&args, const TaskStartParameters &startParameters) {
0178 return (new StoredFunctionCall<Function, Args...>(std::move(args)))
0179 ->start(startParameters);
0180 }
0181 };
0182
0183 template<typename...>
0184 struct PromiseTaskResolver;
0185
0186 template <typename Function, typename ... Args>
0187 struct PromiseTaskResolver<Function, Args...>
0188 {
0189 static_assert(QtPrivate::ArgResolver<Function>::IsPromise::value,
0190 "The first argument of passed callable object isn't a QPromise<T> & type. "
0191 "Did you intend to pass a callable which takes a QPromise<T> & type as a first argument? "
0192 "Otherwise it's not possible to invoke the function with passed arguments.");
0193 using TaskWithArgs = DecayedTuple<Function, Args...>;
0194 static auto run(TaskWithArgs &&args, const TaskStartParameters &startParameters) {
0195 using PromiseType = typename QtPrivate::ArgResolver<Function>::PromiseType;
0196 return (new StoredFunctionCallWithPromise<Function, PromiseType, Args...>(std::move(args)))
0197 ->start(startParameters);
0198 }
0199 };
0200
0201 template <class IsDirectlyInvocable, class Function, class... Args>
0202 struct TaskResolverHelper;
0203
0204 template <class Function, class... Args>
0205 struct TaskResolverHelper<std::true_type, Function, Args...>
0206 : public NonPromiseTaskResolver<Function, Args...>
0207 {
0208 };
0209
0210 template <class Function, class... Args>
0211 struct TaskResolverHelper<std::false_type, Function, Args...>
0212 : public PromiseTaskResolver<Function, Args...>
0213 {
0214 };
0215
0216 template <class Function, class... Args>
0217 struct TaskResolver : public TaskResolverHelper<typename std::is_invocable<std::decay_t<Function>,
0218 std::decay_t<Args>...>::type, Function, Args...>
0219 {
0220 };
0221
0222 }
0223
0224 #endif
0225
0226 QT_END_NAMESPACE
0227
0228 #endif
0229
0230 #endif