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