1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QTCONCURRENT_STOREDFUNCTIONCALL_H
5#define QTCONCURRENT_STOREDFUNCTIONCALL_H
6
7#include <QtConcurrent/qtconcurrent_global.h>
8
9#ifndef QT_NO_CONCURRENT
10#include <QtConcurrent/qtconcurrentrunbase.h>
11#include <QtCore/qpromise.h>
12
13#include <type_traits>
14
15QT_BEGIN_NAMESPACE
16
17#ifndef Q_QDOC
18
19namespace QtConcurrent {
20
21template<typename...>
22struct NonMemberFunctionResolver;
23
24template <class Function, class PromiseType, class... Args>
25struct NonMemberFunctionResolver<Function, PromiseType, Args...>
26{
27 using Type = std::tuple<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>;
28 static_assert(std::is_invocable_v<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>,
29 "It's not possible to invoke the function with passed arguments.");
30 static_assert(std::is_void_v<std::invoke_result_t<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>>,
31 "The function must return void type.");
32
33 static constexpr void invoke(std::decay_t<Function> function, QPromise<PromiseType> &promise,
34 std::decay_t<Args>... args)
35 {
36 std::invoke(function, promise, args...);
37 }
38 static Type initData(Function &&f, QPromise<PromiseType> &promise, Args &&...args)
39 {
40 return Type { std::forward<Function>(f), std::ref(promise), std::forward<Args>(args)... };
41 }
42};
43
44template<typename...>
45struct MemberFunctionResolver;
46
47template <typename Function, typename PromiseType, typename Arg, typename ... Args>
48struct MemberFunctionResolver<Function, PromiseType, Arg, Args...>
49{
50 using Type = std::tuple<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>;
51 static_assert(std::is_invocable_v<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>,
52 "It's not possible to invoke the function with passed arguments.");
53 static_assert(std::is_void_v<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>>,
54 "The function must return void type.");
55
56 static constexpr void invoke(std::decay_t<Function> function, std::decay_t<Arg> object,
57 QPromise<PromiseType> &promise, std::decay_t<Args>... args)
58 {
59 std::invoke(function, object, promise, args...);
60 }
61 static Type initData(Function &&f, QPromise<PromiseType> &promise, Arg &&fa, Args &&...args)
62 {
63 return Type { std::forward<Function>(f), std::forward<Arg>(fa), std::ref(promise), std::forward<Args>(args)... };
64 }
65};
66
67template <class IsMember, class Function, class PromiseType, class... Args>
68struct FunctionResolverHelper;
69
70template <class Function, class PromiseType, class... Args>
71struct FunctionResolverHelper<std::false_type, Function, PromiseType, Args...>
72 : public NonMemberFunctionResolver<Function, PromiseType, Args...>
73{
74};
75
76template <class Function, class PromiseType, class... Args>
77struct FunctionResolverHelper<std::true_type, Function, PromiseType, Args...>
78 : public MemberFunctionResolver<Function, PromiseType, Args...>
79{
80};
81
82template <class Function, class PromiseType, class... Args>
83struct FunctionResolver
84 : public FunctionResolverHelper<typename std::is_member_function_pointer<
85 std::decay_t<Function>>::type, Function, PromiseType, Args...>
86{
87};
88
89template <class Function, class ...Args>
90struct InvokeResult
91{
92 static_assert(std::is_invocable_v<std::decay_t<Function>, std::decay_t<Args>...>,
93 "It's not possible to invoke the function with passed arguments.");
94
95 using Type = std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>;
96};
97
98template <class Function, class ...Args>
99using InvokeResultType = typename InvokeResult<Function, Args...>::Type;
100
101template <class ...Types>
102using DecayedTuple = std::tuple<std::decay_t<Types>...>;
103
104template <class Function, class ...Args>
105struct StoredFunctionCall : public RunFunctionTaskBase<InvokeResultType<Function, Args...>>
106{
107 StoredFunctionCall(DecayedTuple<Function, Args...> &&_data)
108 : data(std::move(_data))
109 {}
110
111protected:
112 void runFunctor() override
113 {
114 constexpr auto invoke = [] (std::decay_t<Function> function,
115 std::decay_t<Args>... args) -> auto {
116 return std::invoke(function, args...);
117 };
118
119 if constexpr (std::is_void_v<InvokeResultType<Function, Args...>>) {
120 std::apply(invoke, std::move(data));
121 } else {
122 auto result = std::apply(invoke, std::move(data));
123
124 using T = InvokeResultType<Function, Args...>;
125 if constexpr (std::is_move_constructible_v<T>)
126 this->promise.reportAndMoveResult(std::move(result));
127 else if constexpr (std::is_copy_constructible_v<T>)
128 this->promise.reportResult(result);
129 }
130 }
131
132private:
133 DecayedTuple<Function, Args...> data;
134};
135
136template <class Function, class PromiseType, class ...Args>
137struct StoredFunctionCallWithPromise : public RunFunctionTaskBase<PromiseType>
138{
139 using Resolver = FunctionResolver<Function, PromiseType, Args...>;
140 using DataType = typename Resolver::Type;
141 StoredFunctionCallWithPromise(Function &&f, Args &&...args)
142 : prom(this->promise),
143 data(std::move(Resolver::initData(std::forward<Function>(f), std::ref(prom),
144 std::forward<Args>(args)...)))
145 {}
146
147 StoredFunctionCallWithPromise(DecayedTuple<Function, Args...> &&_data)
148 : StoredFunctionCallWithPromise(std::move(_data),
149 std::index_sequence_for<std::decay_t<Function>, std::decay_t<Args>...>())
150 {}
151
152protected:
153 void runFunctor() override
154 {
155 std::apply(Resolver::invoke, std::move(data));
156 }
157
158private:
159 // helper to pack back the tuple into parameter pack
160 template<std::size_t... Is>
161 StoredFunctionCallWithPromise(DecayedTuple<Function, Args...> &&_data,
162 std::index_sequence<Is...>)
163 : StoredFunctionCallWithPromise(std::move(std::get<Is>(_data))...)
164 {}
165
166 QPromise<PromiseType> prom;
167 DataType data;
168};
169
170template<typename...>
171struct NonPromiseTaskResolver;
172
173template <typename Function, typename ... Args>
174struct NonPromiseTaskResolver<Function, Args...>
175{
176 using TaskWithArgs = DecayedTuple<Function, Args...>;
177 static auto run(TaskWithArgs &&args, const TaskStartParameters &startParameters) {
178 return (new StoredFunctionCall<Function, Args...>(std::move(args)))
179 ->start(startParameters);
180 }
181};
182
183template<typename...>
184struct PromiseTaskResolver;
185
186template <typename Function, typename ... Args>
187struct PromiseTaskResolver<Function, Args...>
188{
189 static_assert(QtPrivate::ArgResolver<Function>::IsPromise::value,
190 "The first argument of passed callable object isn't a QPromise<T> & type. "
191 "Did you intend to pass a callable which takes a QPromise<T> & type as a first argument? "
192 "Otherwise it's not possible to invoke the function with passed arguments.");
193 using TaskWithArgs = DecayedTuple<Function, Args...>;
194 static auto run(TaskWithArgs &&args, const TaskStartParameters &startParameters) {
195 using PromiseType = typename QtPrivate::ArgResolver<Function>::PromiseType;
196 return (new StoredFunctionCallWithPromise<Function, PromiseType, Args...>(std::move(args)))
197 ->start(startParameters);
198 }
199};
200
201template <class IsDirectlyInvocable, class Function, class... Args>
202struct TaskResolverHelper;
203
204template <class Function, class... Args>
205struct TaskResolverHelper<std::true_type, Function, Args...>
206 : public NonPromiseTaskResolver<Function, Args...>
207{
208};
209
210template <class Function, class... Args>
211struct TaskResolverHelper<std::false_type, Function, Args...>
212 : public PromiseTaskResolver<Function, Args...>
213{
214};
215
216template <class Function, class... Args>
217struct TaskResolver : public TaskResolverHelper<typename std::is_invocable<std::decay_t<Function>,
218 std::decay_t<Args>...>::type, Function, Args...>
219{
220};
221
222} //namespace QtConcurrent
223
224#endif // Q_QDOC
225
226QT_END_NAMESPACE
227
228#endif // QT_NO_CONCURRENT
229
230#endif
231

source code of qtbase/src/concurrent/qtconcurrentstoredfunctioncall.h