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