1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtConcurrent module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #ifndef QTCONCURRENT_STOREDFUNCTIONCALL_H |
41 | #define QTCONCURRENT_STOREDFUNCTIONCALL_H |
42 | |
43 | #include <QtConcurrent/qtconcurrent_global.h> |
44 | |
45 | #ifndef QT_NO_CONCURRENT |
46 | #include <QtConcurrent/qtconcurrentrunbase.h> |
47 | #include <QtCore/qpromise.h> |
48 | |
49 | #include <type_traits> |
50 | |
51 | QT_BEGIN_NAMESPACE |
52 | |
53 | #ifndef Q_QDOC |
54 | |
55 | namespace QtConcurrent { |
56 | |
57 | template<typename...> |
58 | struct NonMemberFunctionResolver; |
59 | |
60 | template <class Function, class PromiseType, class... Args> |
61 | struct NonMemberFunctionResolver<Function, PromiseType, Args...> |
62 | { |
63 | using Type = std::tuple<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>; |
64 | static_assert(std::is_invocable_v<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>, |
65 | "It's not possible to invoke the function with passed arguments." ); |
66 | static_assert(std::is_void_v<std::invoke_result_t<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>>, |
67 | "The function must return void type." ); |
68 | |
69 | static constexpr void invoke(std::decay_t<Function> function, QPromise<PromiseType> &promise, |
70 | std::decay_t<Args>... args) |
71 | { |
72 | std::invoke(function, promise, args...); |
73 | } |
74 | static Type initData(Function &&f, QPromise<PromiseType> &promise, Args &&...args) |
75 | { |
76 | return Type { std::forward<Function>(f), std::ref(promise), std::forward<Args>(args)... }; |
77 | } |
78 | }; |
79 | |
80 | template<typename...> |
81 | struct MemberFunctionResolver; |
82 | |
83 | template <typename Function, typename PromiseType, typename Arg, typename ... Args> |
84 | struct MemberFunctionResolver<Function, PromiseType, Arg, Args...> |
85 | { |
86 | using Type = std::tuple<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>; |
87 | static_assert(std::is_invocable_v<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>, |
88 | "It's not possible to invoke the function with passed arguments." ); |
89 | static_assert(std::is_void_v<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>>, |
90 | "The function must return void type." ); |
91 | |
92 | static constexpr void invoke(std::decay_t<Function> function, std::decay_t<Arg> object, |
93 | QPromise<PromiseType> &promise, std::decay_t<Args>... args) |
94 | { |
95 | std::invoke(function, object, promise, args...); |
96 | } |
97 | static Type initData(Function &&f, QPromise<PromiseType> &promise, Arg &&fa, Args &&...args) |
98 | { |
99 | return Type { std::forward<Function>(f), std::forward<Arg>(fa), std::ref(promise), std::forward<Args>(args)... }; |
100 | } |
101 | }; |
102 | |
103 | template <class IsMember, class Function, class PromiseType, class... Args> |
104 | struct FunctionResolverHelper; |
105 | |
106 | template <class Function, class PromiseType, class... Args> |
107 | struct FunctionResolverHelper<std::false_type, Function, PromiseType, Args...> |
108 | : public NonMemberFunctionResolver<Function, PromiseType, Args...> |
109 | { |
110 | }; |
111 | |
112 | template <class Function, class PromiseType, class... Args> |
113 | struct FunctionResolverHelper<std::true_type, Function, PromiseType, Args...> |
114 | : public MemberFunctionResolver<Function, PromiseType, Args...> |
115 | { |
116 | }; |
117 | |
118 | template <class Function, class PromiseType, class... Args> |
119 | struct FunctionResolver |
120 | : public FunctionResolverHelper<typename std::is_member_function_pointer< |
121 | std::decay_t<Function>>::type, Function, PromiseType, Args...> |
122 | { |
123 | }; |
124 | |
125 | template <class Function, class ...Args> |
126 | struct InvokeResult |
127 | { |
128 | static_assert(std::is_invocable_v<std::decay_t<Function>, std::decay_t<Args>...>, |
129 | "It's not possible to invoke the function with passed arguments." ); |
130 | |
131 | using Type = std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>; |
132 | }; |
133 | |
134 | template <class Function, class ...Args> |
135 | using InvokeResultType = typename InvokeResult<Function, Args...>::Type; |
136 | |
137 | template <class ...Types> |
138 | using DecayedTuple = std::tuple<std::decay_t<Types>...>; |
139 | |
140 | template <class Function, class ...Args> |
141 | struct StoredFunctionCall : public RunFunctionTask<InvokeResultType<Function, Args...>> |
142 | { |
143 | StoredFunctionCall(DecayedTuple<Function, Args...> &&_data) |
144 | : data(std::move(_data)) |
145 | {} |
146 | |
147 | protected: |
148 | void runFunctor() override |
149 | { |
150 | constexpr auto invoke = [] (std::decay_t<Function> function, |
151 | std::decay_t<Args>... args) -> auto { |
152 | return std::invoke(function, args...); |
153 | }; |
154 | |
155 | if constexpr (std::is_void_v<InvokeResultType<Function, Args...>>) |
156 | std::apply(invoke, std::move(data)); |
157 | else |
158 | this->result = std::apply(invoke, std::move(data)); |
159 | } |
160 | |
161 | private: |
162 | DecayedTuple<Function, Args...> data; |
163 | }; |
164 | |
165 | template <class Function, class PromiseType, class ...Args> |
166 | struct StoredFunctionCallWithPromise : public RunFunctionTaskBase<PromiseType> |
167 | { |
168 | using Resolver = FunctionResolver<Function, PromiseType, Args...>; |
169 | using DataType = typename Resolver::Type; |
170 | StoredFunctionCallWithPromise(Function &&f, Args &&...args) |
171 | : prom(this->promise), |
172 | data(std::move(Resolver::initData(std::forward<Function>(f), std::ref(prom), |
173 | std::forward<Args>(args)...))) |
174 | {} |
175 | |
176 | StoredFunctionCallWithPromise(DecayedTuple<Function, Args...> &&_data) |
177 | : StoredFunctionCallWithPromise(std::move(_data), |
178 | std::index_sequence_for<std::decay_t<Function>, std::decay_t<Args>...>()) |
179 | {} |
180 | |
181 | protected: |
182 | void runFunctor() override |
183 | { |
184 | std::apply(Resolver::invoke, std::move(data)); |
185 | } |
186 | |
187 | private: |
188 | // helper to pack back the tuple into parameter pack |
189 | template<std::size_t... Is> |
190 | StoredFunctionCallWithPromise(DecayedTuple<Function, Args...> &&_data, |
191 | std::index_sequence<Is...>) |
192 | : StoredFunctionCallWithPromise(std::move(std::get<Is>(_data))...) |
193 | {} |
194 | |
195 | QPromise<PromiseType> prom; |
196 | DataType data; |
197 | }; |
198 | |
199 | template<typename...> |
200 | struct NonPromiseTaskResolver; |
201 | |
202 | template <typename Function, typename ... Args> |
203 | struct NonPromiseTaskResolver<Function, Args...> |
204 | { |
205 | using TaskWithArgs = DecayedTuple<Function, Args...>; |
206 | static auto run(TaskWithArgs &&args, const TaskStartParameters &startParameters) { |
207 | return (new StoredFunctionCall<Function, Args...>(std::move(args))) |
208 | ->start(startParameters); |
209 | } |
210 | }; |
211 | |
212 | template<typename...> |
213 | struct PromiseTaskResolver; |
214 | |
215 | template <typename Function, typename ... Args> |
216 | struct PromiseTaskResolver<Function, Args...> |
217 | { |
218 | static_assert(QtPrivate::ArgResolver<Function>::IsPromise::value, |
219 | "The first argument of passed callable object isn't a QPromise<T> & type. " |
220 | "Did you intend to pass a callable which takes a QPromise<T> & type as a first argument? " |
221 | "Otherwise it's not possible to invoke the function with passed arguments." ); |
222 | using TaskWithArgs = DecayedTuple<Function, Args...>; |
223 | static auto run(TaskWithArgs &&args, const TaskStartParameters &startParameters) { |
224 | using PromiseType = typename QtPrivate::ArgResolver<Function>::PromiseType; |
225 | return (new StoredFunctionCallWithPromise<Function, PromiseType, Args...>(std::move(args))) |
226 | ->start(startParameters); |
227 | } |
228 | }; |
229 | |
230 | template <class IsDirectlyInvocable, class Function, class... Args> |
231 | struct TaskResolverHelper; |
232 | |
233 | template <class Function, class... Args> |
234 | struct TaskResolverHelper<std::true_type, Function, Args...> |
235 | : public NonPromiseTaskResolver<Function, Args...> |
236 | { |
237 | }; |
238 | |
239 | template <class Function, class... Args> |
240 | struct TaskResolverHelper<std::false_type, Function, Args...> |
241 | : public PromiseTaskResolver<Function, Args...> |
242 | { |
243 | }; |
244 | |
245 | template <class Function, class... Args> |
246 | struct TaskResolver : public TaskResolverHelper<typename std::is_invocable<std::decay_t<Function>, |
247 | std::decay_t<Args>...>::type, Function, Args...> |
248 | { |
249 | }; |
250 | |
251 | } //namespace QtConcurrent |
252 | |
253 | #endif // Q_QDOC |
254 | |
255 | QT_END_NAMESPACE |
256 | |
257 | #endif // QT_NO_CONCURRENT |
258 | |
259 | #endif |
260 | |