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_FILTERKERNEL_H
41#define QTCONCURRENT_FILTERKERNEL_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/qtconcurrentmapkernel.h>
49#include <QtConcurrent/qtconcurrentreducekernel.h>
50
51QT_BEGIN_NAMESPACE
52
53
54
55namespace QtConcurrent {
56
57template <typename T>
58struct qValueType
59{
60 typedef typename T::value_type value_type;
61};
62
63template <typename T>
64struct qValueType<const T*>
65{
66 typedef T value_type;
67};
68
69template <typename T>
70struct qValueType<T*>
71{
72 typedef T value_type;
73};
74
75// Implementation of filter
76template <typename Sequence, typename KeepFunctor, typename ReduceFunctor>
77class FilterKernel : public IterateKernel<typename Sequence::const_iterator, void>
78{
79 typedef ReduceKernel<ReduceFunctor, Sequence, typename Sequence::value_type> Reducer;
80 typedef IterateKernel<typename Sequence::const_iterator, void> IterateKernelType;
81 typedef void T;
82
83 Sequence reducedResult;
84 Sequence &sequence;
85 KeepFunctor keep;
86 ReduceFunctor reduce;
87 Reducer reducer;
88
89public:
90 FilterKernel(QThreadPool *pool, Sequence &_sequence, KeepFunctor _keep, ReduceFunctor _reduce)
91 : IterateKernelType(pool, const_cast<const Sequence &>(_sequence).begin(),
92 const_cast<const Sequence &>(_sequence).end()), reducedResult(),
93 sequence(_sequence),
94 keep(_keep),
95 reduce(_reduce),
96 reducer(pool, OrderedReduce)
97 { }
98
99 bool runIteration(typename Sequence::const_iterator it, int index, T *) override
100 {
101 IntermediateResults<typename Sequence::value_type> results;
102 results.begin = index;
103 results.end = index + 1;
104
105 if (std::invoke(keep, *it))
106 results.vector.append(*it);
107
108 reducer.runReduce(reduce, reducedResult, results);
109 return false;
110 }
111
112 bool runIterations(typename Sequence::const_iterator sequenceBeginIterator, int begin, int end, T *) override
113 {
114 IntermediateResults<typename Sequence::value_type> results;
115 results.begin = begin;
116 results.end = end;
117 results.vector.reserve(end - begin);
118
119
120 typename Sequence::const_iterator it = sequenceBeginIterator;
121 std::advance(it, begin);
122 for (int i = begin; i < end; ++i) {
123 if (std::invoke(keep, *it))
124 results.vector.append(*it);
125 std::advance(it, 1);
126 }
127
128 reducer.runReduce(reduce, reducedResult, results);
129 return false;
130 }
131
132 void finish() override
133 {
134 reducer.finish(reduce, reducedResult);
135 sequence = reducedResult;
136 }
137
138 inline bool shouldThrottleThread() override
139 {
140 return IterateKernelType::shouldThrottleThread() || reducer.shouldThrottle();
141 }
142
143 inline bool shouldStartThread() override
144 {
145 return IterateKernelType::shouldStartThread() && reducer.shouldStartThread();
146 }
147
148 typedef void ReturnType;
149 typedef void ResultType;
150};
151
152// Implementation of filter-reduce
153template <typename ReducedResultType,
154 typename Iterator,
155 typename KeepFunctor,
156 typename ReduceFunctor,
157 typename Reducer = ReduceKernel<ReduceFunctor,
158 ReducedResultType,
159 typename qValueType<Iterator>::value_type> >
160class FilteredReducedKernel : public IterateKernel<Iterator, ReducedResultType>
161{
162 ReducedResultType reducedResult;
163 KeepFunctor keep;
164 ReduceFunctor reduce;
165 Reducer reducer;
166 typedef IterateKernel<Iterator, ReducedResultType> IterateKernelType;
167
168public:
169 FilteredReducedKernel(QThreadPool *pool,
170 Iterator begin,
171 Iterator end,
172 KeepFunctor _keep,
173 ReduceFunctor _reduce,
174 ReduceOptions reduceOption)
175 : IterateKernelType(pool, begin, end), reducedResult(), keep(_keep), reduce(_reduce),
176 reducer(pool, reduceOption)
177 { }
178
179 FilteredReducedKernel(QThreadPool *pool, Iterator begin, Iterator end, KeepFunctor _keep,
180 ReduceFunctor _reduce, ReducedResultType &&initialValue,
181 ReduceOptions reduceOption)
182 : IterateKernelType(pool, begin, end),
183 reducedResult(std::forward<ReducedResultType>(initialValue)),
184 keep(_keep),
185 reduce(_reduce),
186 reducer(pool, reduceOption)
187 {
188 }
189
190 bool runIteration(Iterator it, int index, ReducedResultType *) override
191 {
192 IntermediateResults<typename qValueType<Iterator>::value_type> results;
193 results.begin = index;
194 results.end = index + 1;
195
196 if (std::invoke(keep, *it))
197 results.vector.append(*it);
198
199 reducer.runReduce(reduce, reducedResult, results);
200 return false;
201 }
202
203 bool runIterations(Iterator sequenceBeginIterator, int begin, int end, ReducedResultType *) override
204 {
205 IntermediateResults<typename qValueType<Iterator>::value_type> results;
206 results.begin = begin;
207 results.end = end;
208 results.vector.reserve(end - begin);
209
210 Iterator it = sequenceBeginIterator;
211 std::advance(it, begin);
212 for (int i = begin; i < end; ++i) {
213 if (std::invoke(keep, *it))
214 results.vector.append(*it);
215 std::advance(it, 1);
216 }
217
218 reducer.runReduce(reduce, reducedResult, results);
219 return false;
220 }
221
222 void finish() override
223 {
224 reducer.finish(reduce, reducedResult);
225 }
226
227 inline bool shouldThrottleThread() override
228 {
229 return IterateKernelType::shouldThrottleThread() || reducer.shouldThrottle();
230 }
231
232 inline bool shouldStartThread() override
233 {
234 return IterateKernelType::shouldStartThread() && reducer.shouldStartThread();
235 }
236
237 typedef ReducedResultType ReturnType;
238 typedef ReducedResultType ResultType;
239 ReducedResultType *result() override
240 {
241 return &reducedResult;
242 }
243};
244
245// Implementation of filter that reports individual results via QFutureInterface
246template <typename Iterator, typename KeepFunctor>
247class FilteredEachKernel : public IterateKernel<Iterator, typename qValueType<Iterator>::value_type>
248{
249 typedef typename qValueType<Iterator>::value_type T;
250 typedef IterateKernel<Iterator, T> IterateKernelType;
251
252 KeepFunctor keep;
253
254public:
255 typedef T ReturnType;
256 typedef T ResultType;
257
258 FilteredEachKernel(QThreadPool *pool, Iterator begin, Iterator end, KeepFunctor _keep)
259 : IterateKernelType(pool, begin, end), keep(_keep)
260 { }
261
262 void start() override
263 {
264 if (this->futureInterface)
265 this->futureInterface->setFilterMode(true);
266 IterateKernelType::start();
267 }
268
269 bool runIteration(Iterator it, int index, T *) override
270 {
271 if (std::invoke(keep, *it))
272 this->reportResult(&(*it), index);
273 else
274 this->reportResult(nullptr, index);
275 return false;
276 }
277
278 bool runIterations(Iterator sequenceBeginIterator, int begin, int end, T *) override
279 {
280 const int count = end - begin;
281 IntermediateResults<typename qValueType<Iterator>::value_type> results;
282 results.begin = begin;
283 results.end = end;
284 results.vector.reserve(count);
285
286 Iterator it = sequenceBeginIterator;
287 std::advance(it, begin);
288 for (int i = begin; i < end; ++i) {
289 if (std::invoke(keep, *it))
290 results.vector.append(*it);
291 std::advance(it, 1);
292 }
293
294 this->reportResults(results.vector, begin, count);
295 return false;
296 }
297};
298
299//! [QtConcurrent-2]
300template <typename Iterator, typename KeepFunctor>
301inline
302ThreadEngineStarter<typename qValueType<Iterator>::value_type>
303startFiltered(QThreadPool *pool, Iterator begin, Iterator end, KeepFunctor functor)
304{
305 return startThreadEngine(new FilteredEachKernel<Iterator, KeepFunctor>
306 (pool, begin, end, functor));
307}
308
309//! [QtConcurrent-3]
310template <typename Sequence, typename KeepFunctor>
311inline decltype(auto) startFiltered(QThreadPool *pool, Sequence &&sequence, KeepFunctor functor)
312{
313 using DecayedSequence = std::decay_t<Sequence>;
314 typedef SequenceHolder1<DecayedSequence,
315 FilteredEachKernel<typename DecayedSequence::const_iterator, KeepFunctor>,
316 KeepFunctor>
317 SequenceHolderType;
318 return startThreadEngine(
319 new SequenceHolderType(pool, std::forward<Sequence>(sequence), functor));
320}
321
322//! [QtConcurrent-4]
323template <typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor>
324inline ThreadEngineStarter<ResultType> startFilteredReduced(QThreadPool *pool,
325 Sequence &&sequence,
326 MapFunctor mapFunctor,
327 ReduceFunctor reduceFunctor,
328 ReduceOptions options)
329{
330 using DecayedSequence = std::decay_t<Sequence>;
331 typedef typename DecayedSequence::const_iterator Iterator;
332 typedef ReduceKernel<ReduceFunctor, ResultType, typename qValueType<Iterator>::value_type >
333 Reducer;
334 typedef FilteredReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer>
335 FilteredReduceType;
336 typedef SequenceHolder2<DecayedSequence, FilteredReduceType, MapFunctor, ReduceFunctor>
337 SequenceHolderType;
338 return startThreadEngine(new SequenceHolderType(pool, std::forward<Sequence>(sequence),
339 mapFunctor, reduceFunctor, options));
340}
341
342
343//! [QtConcurrent-5]
344template <typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor>
345inline ThreadEngineStarter<ResultType> startFilteredReduced(QThreadPool *pool,
346 Iterator begin,
347 Iterator end,
348 MapFunctor mapFunctor,
349 ReduceFunctor reduceFunctor,
350 ReduceOptions options)
351{
352 typedef ReduceKernel<ReduceFunctor, ResultType, typename qValueType<Iterator>::value_type>
353 Reducer;
354 typedef FilteredReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer>
355 FilteredReduceType;
356 return startThreadEngine(new FilteredReduceType(pool, begin, end, mapFunctor,
357 reduceFunctor, options));
358}
359
360// Repeat the two functions above, but now with an initial value!
361//! [QtConcurrent-6]
362template <typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor>
363inline ThreadEngineStarter<ResultType> startFilteredReduced(QThreadPool *pool,
364 Sequence &&sequence,
365 MapFunctor mapFunctor,
366 ReduceFunctor reduceFunctor,
367 ResultType &&initialValue,
368 ReduceOptions options)
369{
370 using DecayedSequence = std::decay_t<Sequence>;
371 typedef typename DecayedSequence::const_iterator Iterator;
372 typedef ReduceKernel<ReduceFunctor, ResultType, typename qValueType<Iterator>::value_type >
373 Reducer;
374 typedef FilteredReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer>
375 FilteredReduceType;
376 typedef SequenceHolder2<DecayedSequence, FilteredReduceType, MapFunctor, ReduceFunctor>
377 SequenceHolderType;
378 return startThreadEngine(
379 new SequenceHolderType(pool, std::forward<Sequence>(sequence), mapFunctor,
380 reduceFunctor, std::forward<ResultType>(initialValue), options));
381}
382
383//! [QtConcurrent-7]
384template <typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor>
385inline ThreadEngineStarter<ResultType> startFilteredReduced(QThreadPool *pool,
386 Iterator begin,
387 Iterator end,
388 MapFunctor mapFunctor,
389 ReduceFunctor reduceFunctor,
390 ResultType &&initialValue,
391 ReduceOptions options)
392{
393 typedef ReduceKernel<ReduceFunctor, ResultType, typename qValueType<Iterator>::value_type>
394 Reducer;
395 typedef FilteredReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer>
396 FilteredReduceType;
397 return startThreadEngine(new FilteredReduceType(pool, begin, end, mapFunctor, reduceFunctor,
398 std::forward<ResultType>(initialValue), options));
399}
400
401
402} // namespace QtConcurrent
403
404
405QT_END_NAMESPACE
406
407#endif // QT_NO_CONCURRENT
408
409#endif
410