1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtCore 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 Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QTCONCURRENT_FILTERKERNEL_H
43#define QTCONCURRENT_FILTERKERNEL_H
44
45#include <QtCore/qglobal.h>
46
47#ifndef QT_NO_CONCURRENT
48
49#include <QtCore/qtconcurrentiteratekernel.h>
50#include <QtCore/qtconcurrentmapkernel.h>
51#include <QtCore/qtconcurrentreducekernel.h>
52
53QT_BEGIN_HEADER
54QT_BEGIN_NAMESPACE
55
56QT_MODULE(Core)
57
58#ifndef qdoc
59
60namespace QtConcurrent {
61
62template <typename T>
63struct qValueType
64{
65 typedef typename T::value_type value_type;
66};
67
68template <typename T>
69struct qValueType<const T*>
70{
71 typedef T value_type;
72};
73
74template <typename T>
75struct qValueType<T*>
76{
77 typedef T value_type;
78};
79
80// Implementation of filter
81template <typename Sequence, typename KeepFunctor, typename ReduceFunctor>
82class FilterKernel : public IterateKernel<typename Sequence::const_iterator, void>
83{
84 typedef ReduceKernel<ReduceFunctor, Sequence, typename Sequence::value_type> Reducer;
85 typedef IterateKernel<typename Sequence::const_iterator, void> IterateKernelType;
86 typedef typename ReduceFunctor::result_type T;
87
88 Sequence reducedResult;
89 Sequence &sequence;
90 KeepFunctor keep;
91 ReduceFunctor reduce;
92 Reducer reducer;
93
94public:
95 FilterKernel(Sequence &_sequence, KeepFunctor _keep, ReduceFunctor _reduce)
96 : IterateKernelType(const_cast<const Sequence &>(_sequence).begin(), const_cast<const Sequence &>(_sequence).end()), reducedResult(),
97 sequence(_sequence),
98 keep(_keep),
99 reduce(_reduce),
100 reducer(OrderedReduce)
101 { }
102
103 bool runIteration(typename Sequence::const_iterator it, int index, T *)
104 {
105 IntermediateResults<typename Sequence::value_type> results;
106 results.begin = index;
107 results.end = index + 1;
108
109 if (keep(*it))
110 results.vector.append(*it);
111
112 reducer.runReduce(reduce, reducedResult, results);
113 return false;
114 }
115
116 bool runIterations(typename Sequence::const_iterator sequenceBeginIterator, int begin, int end, T *)
117 {
118 IntermediateResults<typename Sequence::value_type> results;
119 results.begin = begin;
120 results.end = end;
121 results.vector.reserve(end - begin);
122
123
124 typename Sequence::const_iterator it = sequenceBeginIterator;
125 advance(it, begin);
126 for (int i = begin; i < end; ++i) {
127 if (keep(*it))
128 results.vector.append(*it);
129 advance(it, 1);
130 }
131
132 reducer.runReduce(reduce, reducedResult, results);
133 return false;
134 }
135
136 void finish()
137 {
138 reducer.finish(reduce, reducedResult);
139 sequence = reducedResult;
140 }
141
142 inline bool shouldThrottleThread()
143 {
144 return IterateKernelType::shouldThrottleThread() || reducer.shouldThrottle();
145 }
146
147 inline bool shouldStartThread()
148 {
149 return IterateKernelType::shouldStartThread() && reducer.shouldStartThread();
150 }
151
152 typedef void ReturnType;
153 typedef void ResultType;
154};
155
156// Implementation of filter-reduce
157template <typename ReducedResultType,
158 typename Iterator,
159 typename KeepFunctor,
160 typename ReduceFunctor,
161 typename Reducer = ReduceKernel<ReduceFunctor,
162 ReducedResultType,
163 typename qValueType<Iterator>::value_type> >
164class FilteredReducedKernel : public IterateKernel<Iterator, ReducedResultType>
165{
166 ReducedResultType reducedResult;
167 KeepFunctor keep;
168 ReduceFunctor reduce;
169 Reducer reducer;
170 typedef IterateKernel<Iterator, ReducedResultType> IterateKernelType;
171
172public:
173 FilteredReducedKernel(Iterator begin,
174 Iterator end,
175 KeepFunctor _keep,
176 ReduceFunctor _reduce,
177 ReduceOptions reduceOption)
178 : IterateKernelType(begin, end), reducedResult(), keep(_keep), reduce(_reduce), reducer(reduceOption)
179 { }
180
181#if 0
182 FilteredReducedKernel(ReducedResultType initialValue,
183 KeepFunctor keep,
184 ReduceFunctor reduce,
185 ReduceOption reduceOption)
186 : reducedResult(initialValue), keep(keep), reduce(reduce), reducer(reduceOption)
187 { }
188#endif
189
190 bool runIteration(Iterator it, int index, ReducedResultType *)
191 {
192 IntermediateResults<typename qValueType<Iterator>::value_type> results;
193 results.begin = index;
194 results.end = index + 1;
195
196 if (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 *)
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 advance(it, begin);
212 for (int i = begin; i < end; ++i) {
213 if (keep(*it))
214 results.vector.append(*it);
215 advance(it, 1);
216 }
217
218 reducer.runReduce(reduce, reducedResult, results);
219 return false;
220 }
221
222 void finish()
223 {
224 reducer.finish(reduce, reducedResult);
225 }
226
227 inline bool shouldThrottleThread()
228 {
229 return IterateKernelType::shouldThrottleThread() || reducer.shouldThrottle();
230 }
231
232 inline bool shouldStartThread()
233 {
234 return IterateKernelType::shouldStartThread() && reducer.shouldStartThread();
235 }
236
237 typedef ReducedResultType ReturnType;
238 typedef ReducedResultType ResultType;
239 ReducedResultType *result()
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(Iterator begin, Iterator end, KeepFunctor _keep)
259 : IterateKernelType(begin, end), keep(_keep)
260 { }
261
262 void start()
263 {
264 if (this->futureInterface)
265 this->futureInterface->setFilterMode(true);
266 IterateKernelType::start();
267 }
268
269 bool runIteration(Iterator it, int index, T *)
270 {
271 if (keep(*it))
272 this->reportResult(&(*it), index);
273 else
274 this->reportResult(0, index);
275 return false;
276 }
277
278 bool runIterations(Iterator sequenceBeginIterator, int begin, int end, T *)
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 advance(it, begin);
288 for (int i = begin; i < end; ++i) {
289 if (keep(*it))
290 results.vector.append(*it);
291 advance(it, 1);
292 }
293
294 this->reportResults(results.vector, begin, count);
295 return false;
296 }
297};
298
299template <typename Iterator, typename KeepFunctor>
300inline
301ThreadEngineStarter<typename qValueType<Iterator>::value_type>
302startFiltered(Iterator begin, Iterator end, KeepFunctor functor)
303{
304 return startThreadEngine(new FilteredEachKernel<Iterator, KeepFunctor>(begin, end, functor));
305}
306
307template <typename Sequence, typename KeepFunctor>
308inline ThreadEngineStarter<typename Sequence::value_type>
309startFiltered(const Sequence &sequence, KeepFunctor functor)
310{
311 typedef SequenceHolder1<Sequence,
312 FilteredEachKernel<typename Sequence::const_iterator, KeepFunctor>,
313 KeepFunctor>
314 SequenceHolderType;
315 return startThreadEngine(new SequenceHolderType(sequence, functor));
316}
317
318template <typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor>
319inline ThreadEngineStarter<ResultType> startFilteredReduced(const Sequence & sequence,
320 MapFunctor mapFunctor, ReduceFunctor reduceFunctor,
321 ReduceOptions options)
322{
323 typedef typename Sequence::const_iterator Iterator;
324 typedef ReduceKernel<ReduceFunctor, ResultType, typename qValueType<Iterator>::value_type > Reducer;
325 typedef FilteredReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer> FilteredReduceType;
326 typedef SequenceHolder2<Sequence, FilteredReduceType, MapFunctor, ReduceFunctor> SequenceHolderType;
327 return startThreadEngine(new SequenceHolderType(sequence, mapFunctor, reduceFunctor, options));
328}
329
330
331template <typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor>
332inline ThreadEngineStarter<ResultType> startFilteredReduced(Iterator begin, Iterator end,
333 MapFunctor mapFunctor, ReduceFunctor reduceFunctor,
334 ReduceOptions options)
335{
336 typedef ReduceKernel<ReduceFunctor, ResultType, typename qValueType<Iterator>::value_type> Reducer;
337 typedef FilteredReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer> FilteredReduceType;
338 return startThreadEngine(new FilteredReduceType(begin, end, mapFunctor, reduceFunctor, options));
339}
340
341
342} // namespace QtConcurrent
343
344#endif // qdoc
345
346QT_END_NAMESPACE
347QT_END_HEADER
348
349#endif // QT_NO_CONCURRENT
350
351#endif
352