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 | |
15 | QT_BEGIN_NAMESPACE |
16 | |
17 | |
18 | namespace QtConcurrent { |
19 | |
20 | // map kernel, works with both parallel-for and parallel-while |
21 | template <typename Iterator, typename MapFunctor> |
22 | class MapKernel : public IterateKernel<Iterator, void> |
23 | { |
24 | MapFunctor map; |
25 | public: |
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 | |
51 | template <typename ReducedResultType, |
52 | typename Iterator, |
53 | typename MapFunctor, |
54 | typename ReduceFunctor, |
55 | typename Reducer = ReduceKernel<ReduceFunctor, |
56 | ReducedResultType, |
57 | QtPrivate::MapResultType<Iterator, MapFunctor>>> |
58 | class 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 | |
66 | public: |
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 | |
142 | template <typename Iterator, typename MapFunctor> |
143 | class MappedEachKernel : public IterateKernel<Iterator, QtPrivate::MapResultType<Iterator, MapFunctor>> |
144 | { |
145 | MapFunctor map; |
146 | using T = QtPrivate::MapResultType<Iterator, MapFunctor>; |
147 | |
148 | public: |
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] |
175 | template <typename Iterator, typename Functor> |
176 | inline 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] |
184 | template <typename T, typename Iterator, typename Functor> |
185 | inline 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 | */ |
196 | template <typename Sequence, typename Base, typename Functor> |
197 | struct 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] |
215 | template <typename T, typename Sequence, typename Functor> |
216 | inline 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] |
231 | template <typename IntermediateType, typename ResultType, typename Sequence, typename MapFunctor, |
232 | typename ReduceFunctor> |
233 | inline 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] |
255 | template <typename IntermediateType, typename ResultType, typename Iterator, typename MapFunctor, |
256 | typename ReduceFunctor> |
257 | inline 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] |
275 | template <typename IntermediateType, typename ResultType, typename Sequence, typename MapFunctor, |
276 | typename ReduceFunctor> |
277 | inline 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] |
301 | template <typename IntermediateType, typename ResultType, typename Iterator, typename MapFunctor, |
302 | typename ReduceFunctor> |
303 | inline 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 | |
323 | QT_END_NAMESPACE |
324 | |
325 | #endif // QT_NO_CONCURRENT |
326 | |
327 | #endif |
328 | |