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

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