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
51QT_BEGIN_NAMESPACE
52
53#ifndef Q_QDOC
54
55namespace QtConcurrent {
56
57template<typename...>
58struct NonMemberFunctionResolver;
59
60template <class Function, class PromiseType, class... Args>
61struct 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 decltype (auto) invokePointer()
70 {
71 return &std::invoke<std::decay_t<Function>, QPromise<PromiseType> &, std::decay_t<Args>...>;
72 }
73 static Type initData(Function &&f, QPromise<PromiseType> &promise, Args &&...args)
74 {
75 return Type { std::forward<Function>(f), std::ref(promise), std::forward<Args>(args)... };
76 }
77};
78
79template<typename...>
80struct MemberFunctionResolver;
81
82template <typename Function, typename PromiseType, typename Arg, typename ... Args>
83struct MemberFunctionResolver<Function, PromiseType, Arg, Args...>
84{
85 using Type = std::tuple<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>;
86 static_assert(std::is_invocable_v<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>,
87 "It's not possible to invoke the function with passed arguments.");
88 static_assert(std::is_void_v<std::invoke_result_t<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>>,
89 "The function must return void type.");
90
91 static constexpr decltype (auto) invokePointer()
92 {
93 return &std::invoke<std::decay_t<Function>, std::decay_t<Arg>, QPromise<PromiseType> &, std::decay_t<Args>...>;
94 }
95 static Type initData(Function &&f, QPromise<PromiseType> &promise, Arg &&fa, Args &&...args)
96 {
97 return Type { std::forward<Function>(f), std::forward<Arg>(fa), std::ref(promise), std::forward<Args>(args)... };
98 }
99};
100
101template <class IsMember, class Function, class PromiseType, class... Args>
102struct FunctionResolverHelper;
103
104template <class Function, class PromiseType, class... Args>
105struct FunctionResolverHelper<std::false_type, Function, PromiseType, Args...> : public NonMemberFunctionResolver<Function, PromiseType, Args...>
106{
107};
108
109template <class Function, class PromiseType, class... Args>
110struct FunctionResolverHelper<std::true_type, Function, PromiseType, Args...> : public MemberFunctionResolver<Function, PromiseType, Args...>
111{
112};
113
114template <class Function, class PromiseType, class... Args>
115struct FunctionResolver : public FunctionResolverHelper<typename std::is_member_function_pointer<std::decay_t<Function>>::type, Function, PromiseType, Args...>
116{
117};
118
119template <class Function, class ...Args>
120struct InvokeResult
121{
122 static_assert(std::is_invocable_v<std::decay_t<Function>, std::decay_t<Args>...>,
123 "It's not possible to invoke the function with passed arguments.");
124
125 using Type = std::invoke_result_t<std::decay_t<Function>, std::decay_t<Args>...>;
126};
127
128template <class Function, class ...Args>
129using InvokeResultType = typename InvokeResult<Function, Args...>::Type;
130
131template <class ...Types>
132using DecayedTuple = std::tuple<std::decay_t<Types>...>;
133
134template <class Function, class ...Args>
135struct StoredFunctionCall : public RunFunctionTask<InvokeResultType<Function, Args...>>
136{
137 StoredFunctionCall(Function &&f, Args &&...args)
138 : data{std::forward<Function>(f), std::forward<Args>(args)...}
139 {}
140
141 StoredFunctionCall(DecayedTuple<Function, Args...> &&_data)
142 : data(std::move(_data))
143 {}
144
145protected:
146 void runFunctor() override
147 {
148 constexpr auto invoke = &std::invoke<std::decay_t<Function>,
149 std::decay_t<Args>...>;
150
151 if constexpr (std::is_void_v<InvokeResultType<Function, Args...>>)
152 std::apply(invoke, std::move(data));
153 else
154 this->result = std::apply(invoke, std::move(data));
155 }
156
157private:
158 DecayedTuple<Function, Args...> data;
159};
160
161template <class Function, class PromiseType, class ...Args>
162struct StoredFunctionCallWithPromise : public RunFunctionTaskBase<PromiseType>
163{
164 using Resolver = FunctionResolver<Function, PromiseType, Args...>;
165 using DataType = typename Resolver::Type;
166 StoredFunctionCallWithPromise(Function &&f, Args &&...args)
167 : prom(this->promise),
168 data(std::move(Resolver::initData(std::forward<Function>(f), std::ref(prom), std::forward<Args>(args)...)))
169 {}
170
171 StoredFunctionCallWithPromise(DataType &&_data)
172 : data(std::move(_data))
173 {}
174
175protected:
176 void runFunctor() override
177 {
178 std::apply(Resolver::invokePointer(), std::move(data));
179 }
180
181private:
182 QPromise<PromiseType> prom;
183 DataType data;
184};
185
186} //namespace QtConcurrent
187
188#endif // Q_QDOC
189
190QT_END_NAMESPACE
191
192#endif // QT_NO_CONCURRENT
193
194#endif
195