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_MAPKERNEL_H
41#define QTCONCURRENT_MAPKERNEL_H
42
43#include <QtConcurrent/qtconcurrent_global.h>
44
45#if !defined(QT_NO_CONCURRENT) || defined (Q_CLANG_QDOC)
46
47#include <QtConcurrent/qtconcurrentiteratekernel.h>
48#include <QtConcurrent/qtconcurrentreducekernel.h>
49#include <QtConcurrent/qtconcurrentfunctionwrappers.h>
50
51QT_BEGIN_NAMESPACE
52
53
54namespace QtConcurrent {
55
56// map kernel, works with both parallel-for and parallel-while
57template <typename Iterator, typename MapFunctor>
58class MapKernel : public IterateKernel<Iterator, void>
59{
60 MapFunctor map;
61public:
62 typedef void ReturnType;
63 MapKernel(QThreadPool *pool, Iterator begin, Iterator end, MapFunctor _map)
64 : IterateKernel<Iterator, void>(pool, begin, end), map(_map)
65 { }
66
67 bool runIteration(Iterator it, int, void *) override
68 {
69 std::invoke(map, *it);
70 return false;
71 }
72
73 bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, void *) override
74 {
75 Iterator it = sequenceBeginIterator;
76 std::advance(it, beginIndex);
77 for (int i = beginIndex; i < endIndex; ++i) {
78 runIteration(it, i, nullptr);
79 std::advance(it, 1);
80 }
81
82 return false;
83 }
84};
85
86template <typename ReducedResultType,
87 typename Iterator,
88 typename MapFunctor,
89 typename ReduceFunctor,
90 typename Reducer = ReduceKernel<ReduceFunctor,
91 ReducedResultType,
92 QtPrivate::MapResultType<Iterator, MapFunctor>>>
93class MappedReducedKernel : public IterateKernel<Iterator, ReducedResultType>
94{
95 ReducedResultType reducedResult;
96 MapFunctor map;
97 ReduceFunctor reduce;
98 Reducer reducer;
99 using IntermediateResultsType = QtPrivate::MapResultType<Iterator, MapFunctor>;
100
101public:
102 typedef ReducedResultType ReturnType;
103 MappedReducedKernel(QThreadPool *pool, Iterator begin, Iterator end, MapFunctor _map,
104 ReduceFunctor _reduce, ReduceOptions reduceOptions)
105 : IterateKernel<Iterator, ReducedResultType>(pool, begin, end), reducedResult(),
106 map(_map), reduce(_reduce), reducer(pool, reduceOptions)
107 { }
108
109 MappedReducedKernel(QThreadPool *pool, Iterator begin, Iterator end, MapFunctor _map,
110 ReduceFunctor _reduce, ReducedResultType &&initialValue,
111 ReduceOptions reduceOptions)
112 : IterateKernel<Iterator, ReducedResultType>(pool, begin, end),
113 reducedResult(std::forward<ReducedResultType>(initialValue)),
114 map(_map),
115 reduce(_reduce),
116 reducer(pool, reduceOptions)
117 {
118 }
119
120 bool runIteration(Iterator it, int index, ReducedResultType *) override
121 {
122 IntermediateResults<IntermediateResultsType> results;
123 results.begin = index;
124 results.end = index + 1;
125
126 results.vector.append(std::invoke(map, *it));
127 reducer.runReduce(reduce, reducedResult, results);
128 return false;
129 }
130
131 bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, ReducedResultType *) override
132 {
133 IntermediateResults<IntermediateResultsType> results;
134 results.begin = beginIndex;
135 results.end = endIndex;
136 results.vector.reserve(endIndex - beginIndex);
137
138 Iterator it = sequenceBeginIterator;
139 std::advance(it, beginIndex);
140 for (int i = beginIndex; i < endIndex; ++i) {
141 results.vector.append(std::invoke(map, *it));
142 std::advance(it, 1);
143 }
144
145 reducer.runReduce(reduce, reducedResult, results);
146 return false;
147 }
148
149 void finish() override
150 {
151 reducer.finish(reduce, reducedResult);
152 }
153
154 bool shouldThrottleThread() override
155 {
156 return IterateKernel<Iterator, ReducedResultType>::shouldThrottleThread() || reducer.shouldThrottle();
157 }
158
159 bool shouldStartThread() override
160 {
161 return IterateKernel<Iterator, ReducedResultType>::shouldStartThread() && reducer.shouldStartThread();
162 }
163
164 typedef ReducedResultType ResultType;
165 ReducedResultType *result() override
166 {
167 return &reducedResult;
168 }
169};
170
171template <typename Iterator, typename MapFunctor>
172class MappedEachKernel : public IterateKernel<Iterator, QtPrivate::MapResultType<Iterator, MapFunctor>>
173{
174 MapFunctor map;
175 using T = QtPrivate::MapResultType<Iterator, MapFunctor>;
176
177public:
178 MappedEachKernel(QThreadPool *pool, Iterator begin, Iterator end, MapFunctor _map)
179 : IterateKernel<Iterator, T>(pool, begin, end), map(_map) { }
180
181 bool runIteration(Iterator it, int, T *result) override
182 {
183 *result = std::invoke(map, *it);
184 return true;
185 }
186
187 bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, T *results) override
188 {
189
190 Iterator it = sequenceBeginIterator;
191 std::advance(it, beginIndex);
192 for (int i = beginIndex; i < endIndex; ++i) {
193 runIteration(it, i, results + (i - beginIndex));
194 std::advance(it, 1);
195 }
196
197 return true;
198 }
199};
200
201//! [qtconcurrentmapkernel-1]
202template <typename Iterator, typename Functor>
203inline ThreadEngineStarter<void> startMap(QThreadPool *pool, Iterator begin,
204 Iterator end, Functor functor)
205{
206 return startThreadEngine(new MapKernel<Iterator, Functor>(pool, begin, end, functor));
207}
208
209//! [qtconcurrentmapkernel-2]
210template <typename T, typename Iterator, typename Functor>
211inline ThreadEngineStarter<T> startMapped(QThreadPool *pool, Iterator begin,
212 Iterator end, Functor functor)
213{
214 return startThreadEngine(new MappedEachKernel<Iterator, Functor>(pool, begin, end, functor));
215}
216
217/*
218 The SequnceHolder class is used to hold a reference to the
219 sequence we are working on.
220*/
221template <typename Sequence, typename Base, typename Functor>
222struct SequenceHolder1 : private QtPrivate::SequenceHolder<Sequence>, public Base
223{
224 SequenceHolder1(QThreadPool *pool, Sequence &&_sequence, Functor functor)
225 : QtPrivate::SequenceHolder<Sequence>(std::move(_sequence)),
226 Base(pool, this->sequence.cbegin(), this->sequence.cend(), functor)
227 { }
228
229 SequenceHolder1(QThreadPool *pool, const Sequence &_sequence, Functor functor)
230 : QtPrivate::SequenceHolder<Sequence>(_sequence),
231 Base(pool, this->sequence.cbegin(), this->sequence.cend(), functor)
232 { }
233
234 void finish() override
235 {
236 Base::finish();
237 // Clear the sequence to make sure all temporaries are destroyed
238 // before finished is signaled.
239 this->sequence = Sequence();
240 }
241};
242
243//! [qtconcurrentmapkernel-3]
244template <typename T, typename Sequence, typename Functor>
245inline ThreadEngineStarter<T> startMapped(QThreadPool *pool, Sequence &&sequence,
246 Functor functor)
247{
248 using DecayedSequence = std::decay_t<Sequence>;
249 typedef SequenceHolder1<DecayedSequence,
250 MappedEachKernel<typename DecayedSequence::const_iterator, Functor>,
251 Functor>
252 SequenceHolderType;
253
254 return startThreadEngine(
255 new SequenceHolderType(pool, std::forward<Sequence>(sequence), functor));
256}
257
258//! [qtconcurrentmapkernel-4]
259template <typename IntermediateType, typename ResultType, typename Sequence, typename MapFunctor,
260 typename ReduceFunctor>
261inline ThreadEngineStarter<ResultType> startMappedReduced(QThreadPool *pool,
262 Sequence &&sequence,
263 MapFunctor mapFunctor,
264 ReduceFunctor reduceFunctor,
265 ReduceOptions options)
266{
267 using DecayedSequence = std::decay_t<Sequence>;
268 typedef typename DecayedSequence::const_iterator Iterator;
269 typedef ReduceKernel<ReduceFunctor, ResultType, IntermediateType> Reducer;
270 typedef MappedReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer>
271 MappedReduceType;
272 typedef SequenceHolder2<DecayedSequence, MappedReduceType, MapFunctor, ReduceFunctor>
273 SequenceHolderType;
274 return startThreadEngine(new SequenceHolderType(pool, std::forward<Sequence>(sequence),
275 mapFunctor, reduceFunctor, options));
276}
277
278//! [qtconcurrentmapkernel-5]
279template <typename IntermediateType, typename ResultType, typename Iterator, typename MapFunctor,
280 typename ReduceFunctor>
281inline ThreadEngineStarter<ResultType> startMappedReduced(QThreadPool *pool,
282 Iterator begin,
283 Iterator end,
284 MapFunctor mapFunctor,
285 ReduceFunctor reduceFunctor,
286 ReduceOptions options)
287{
288 typedef ReduceKernel<ReduceFunctor, ResultType, IntermediateType> Reducer;
289 typedef MappedReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer>
290 MappedReduceType;
291 return startThreadEngine(new MappedReduceType(pool, begin, end, mapFunctor, reduceFunctor,
292 options));
293}
294
295//! [qtconcurrentmapkernel-6]
296template <typename IntermediateType, typename ResultType, typename Sequence, typename MapFunctor,
297 typename ReduceFunctor>
298inline ThreadEngineStarter<ResultType> startMappedReduced(QThreadPool *pool,
299 Sequence &&sequence,
300 MapFunctor mapFunctor,
301 ReduceFunctor reduceFunctor,
302 ResultType &&initialValue,
303 ReduceOptions options)
304{
305 using DecayedSequence = std::decay_t<Sequence>;
306 typedef typename DecayedSequence::const_iterator Iterator;
307 typedef ReduceKernel<ReduceFunctor, ResultType, IntermediateType> Reducer;
308 typedef MappedReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer>
309 MappedReduceType;
310 typedef SequenceHolder2<DecayedSequence, MappedReduceType, MapFunctor, ReduceFunctor>
311 SequenceHolderType;
312 return startThreadEngine(
313 new SequenceHolderType(pool, std::forward<Sequence>(sequence), mapFunctor,
314 reduceFunctor, std::forward<ResultType>(initialValue), options));
315}
316
317//! [qtconcurrentmapkernel-7]
318template <typename IntermediateType, typename ResultType, typename Iterator, typename MapFunctor,
319 typename ReduceFunctor>
320inline ThreadEngineStarter<ResultType> startMappedReduced(QThreadPool *pool,
321 Iterator begin,
322 Iterator end,
323 MapFunctor mapFunctor,
324 ReduceFunctor reduceFunctor,
325 ResultType &&initialValue,
326 ReduceOptions options)
327{
328 typedef ReduceKernel<ReduceFunctor, ResultType, IntermediateType> Reducer;
329 typedef MappedReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer>
330 MappedReduceType;
331 return startThreadEngine(new MappedReduceType(pool, begin, end, mapFunctor, reduceFunctor,
332 std::forward<ResultType>(initialValue), options));
333}
334
335} // namespace QtConcurrent
336
337
338QT_END_NAMESPACE
339
340#endif // QT_NO_CONCURRENT
341
342#endif
343