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_MAPKERNEL_H
41 #define QTCONCURRENT_MAPKERNEL_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/qtconcurrentreducekernel.h>
49 
50 QT_BEGIN_NAMESPACE
51 
52 
53 namespace QtConcurrent {
54 
55 // map kernel, works with both parallel-for and parallel-while
56 template <typename Iterator, typename MapFunctor>
57 class MapKernel : public IterateKernel<Iterator, void>
58 {
59     MapFunctor map;
60 public:
61     typedef void ReturnType;
MapKernel(Iterator begin,Iterator end,MapFunctor _map)62     MapKernel(Iterator begin, Iterator end, MapFunctor _map)
63         : IterateKernel<Iterator, void>(begin, end), map(_map)
64     { }
65 
runIteration(Iterator it,int,void *)66     bool runIteration(Iterator it, int, void *) override
67     {
68         map(*it);
69         return false;
70     }
71 
runIterations(Iterator sequenceBeginIterator,int beginIndex,int endIndex,void *)72     bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, void *) override
73     {
74         Iterator it = sequenceBeginIterator;
75         std::advance(it, beginIndex);
76         for (int i = beginIndex; i < endIndex; ++i) {
77             runIteration(it, i, nullptr);
78             std::advance(it, 1);
79         }
80 
81         return false;
82     }
83 };
84 
85 template <typename ReducedResultType,
86           typename Iterator,
87           typename MapFunctor,
88           typename ReduceFunctor,
89           typename Reducer = ReduceKernel<ReduceFunctor,
90                                           ReducedResultType,
91                                           typename MapFunctor::result_type> >
92 class MappedReducedKernel : public IterateKernel<Iterator, ReducedResultType>
93 {
94     ReducedResultType reducedResult;
95     MapFunctor map;
96     ReduceFunctor reduce;
97     Reducer reducer;
98 public:
99     typedef ReducedResultType ReturnType;
MappedReducedKernel(Iterator begin,Iterator end,MapFunctor _map,ReduceFunctor _reduce,ReduceOptions reduceOptions)100     MappedReducedKernel(Iterator begin, Iterator end, MapFunctor _map, ReduceFunctor _reduce, ReduceOptions reduceOptions)
101         : IterateKernel<Iterator, ReducedResultType>(begin, end), reducedResult(), map(_map), reduce(_reduce), reducer(reduceOptions)
102     { }
103 
MappedReducedKernel(ReducedResultType initialValue,MapFunctor _map,ReduceFunctor _reduce)104     MappedReducedKernel(ReducedResultType initialValue,
105                      MapFunctor _map,
106                      ReduceFunctor _reduce)
107         : reducedResult(initialValue), map(_map), reduce(_reduce)
108     { }
109 
runIteration(Iterator it,int index,ReducedResultType *)110     bool runIteration(Iterator it, int index, ReducedResultType *) override
111     {
112         IntermediateResults<typename MapFunctor::result_type> results;
113         results.begin = index;
114         results.end = index + 1;
115 
116         results.vector.append(map(*it));
117         reducer.runReduce(reduce, reducedResult, results);
118         return false;
119     }
120 
runIterations(Iterator sequenceBeginIterator,int beginIndex,int endIndex,ReducedResultType *)121     bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, ReducedResultType *) override
122     {
123         IntermediateResults<typename MapFunctor::result_type> results;
124         results.begin = beginIndex;
125         results.end = endIndex;
126         results.vector.reserve(endIndex - beginIndex);
127 
128         Iterator it = sequenceBeginIterator;
129         std::advance(it, beginIndex);
130         for (int i = beginIndex; i < endIndex; ++i) {
131             results.vector.append(map(*(it)));
132             std::advance(it, 1);
133         }
134 
135         reducer.runReduce(reduce, reducedResult, results);
136         return false;
137     }
138 
finish()139     void finish() override
140     {
141         reducer.finish(reduce, reducedResult);
142     }
143 
shouldThrottleThread()144     bool shouldThrottleThread() override
145     {
146         return IterateKernel<Iterator, ReducedResultType>::shouldThrottleThread() || reducer.shouldThrottle();
147     }
148 
shouldStartThread()149     bool shouldStartThread() override
150     {
151         return IterateKernel<Iterator, ReducedResultType>::shouldStartThread() && reducer.shouldStartThread();
152     }
153 
154     typedef ReducedResultType ResultType;
result()155     ReducedResultType *result() override
156     {
157         return &reducedResult;
158     }
159 };
160 
161 template <typename Iterator, typename MapFunctor>
162 class MappedEachKernel : public IterateKernel<Iterator, typename MapFunctor::result_type>
163 {
164     MapFunctor map;
165     typedef typename MapFunctor::result_type T;
166 public:
167     typedef T ReturnType;
168     typedef T ResultType;
169 
MappedEachKernel(Iterator begin,Iterator end,MapFunctor _map)170     MappedEachKernel(Iterator begin, Iterator end, MapFunctor _map)
171         : IterateKernel<Iterator, T>(begin, end), map(_map) { }
172 
runIteration(Iterator it,int,T * result)173     bool runIteration(Iterator it, int,  T *result) override
174     {
175         *result = map(*it);
176         return true;
177     }
178 
runIterations(Iterator sequenceBeginIterator,int beginIndex,int endIndex,T * results)179     bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, T *results) override
180     {
181 
182         Iterator it = sequenceBeginIterator;
183         std::advance(it, beginIndex);
184         for (int i = beginIndex; i < endIndex; ++i) {
185             runIteration(it, i, results + (i - beginIndex));
186             std::advance(it, 1);
187         }
188 
189         return true;
190     }
191 };
192 
193 //! [qtconcurrentmapkernel-1]
194 template <typename Iterator, typename Functor>
startMap(Iterator begin,Iterator end,Functor functor)195 inline ThreadEngineStarter<void> startMap(Iterator begin, Iterator end, Functor functor)
196 {
197     return startThreadEngine(new MapKernel<Iterator, Functor>(begin, end, functor));
198 }
199 
200 //! [qtconcurrentmapkernel-2]
201 template <typename T, typename Iterator, typename Functor>
startMapped(Iterator begin,Iterator end,Functor functor)202 inline ThreadEngineStarter<T> startMapped(Iterator begin, Iterator end, Functor functor)
203 {
204     return startThreadEngine(new MappedEachKernel<Iterator, Functor>(begin, end, functor));
205 }
206 
207 /*
208     The SequnceHolder class is used to hold a reference to the
209     sequence we are working on.
210 */
211 template <typename Sequence, typename Base, typename Functor>
212 struct SequenceHolder1 : public Base
213 {
SequenceHolder1SequenceHolder1214     SequenceHolder1(const Sequence &_sequence, Functor functor)
215         : Base(_sequence.begin(), _sequence.end(), functor), sequence(_sequence)
216     { }
217 
218     Sequence sequence;
219 
finishSequenceHolder1220     void finish() override
221     {
222         Base::finish();
223         // Clear the sequence to make sure all temporaries are destroyed
224         // before finished is signaled.
225         sequence = Sequence();
226     }
227 };
228 
229 //! [qtconcurrentmapkernel-3]
230 template <typename T, typename Sequence, typename Functor>
startMapped(const Sequence & sequence,Functor functor)231 inline ThreadEngineStarter<T> startMapped(const Sequence &sequence, Functor functor)
232 {
233     typedef SequenceHolder1<Sequence,
234                             MappedEachKernel<typename Sequence::const_iterator , Functor>, Functor>
235                             SequenceHolderType;
236 
237     return startThreadEngine(new SequenceHolderType(sequence, functor));
238 }
239 
240 //! [qtconcurrentmapkernel-4]
241 template <typename IntermediateType, typename ResultType, typename Sequence, typename MapFunctor, typename ReduceFunctor>
startMappedReduced(const Sequence & sequence,MapFunctor mapFunctor,ReduceFunctor reduceFunctor,ReduceOptions options)242 inline ThreadEngineStarter<ResultType> startMappedReduced(const Sequence & sequence,
243                                                            MapFunctor mapFunctor, ReduceFunctor reduceFunctor,
244                                                            ReduceOptions options)
245 {
246     typedef typename Sequence::const_iterator Iterator;
247     typedef ReduceKernel<ReduceFunctor, ResultType, IntermediateType> Reducer;
248     typedef MappedReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer> MappedReduceType;
249     typedef SequenceHolder2<Sequence, MappedReduceType, MapFunctor, ReduceFunctor> SequenceHolderType;
250     return startThreadEngine(new SequenceHolderType(sequence, mapFunctor, reduceFunctor, options));
251 }
252 
253 //! [qtconcurrentmapkernel-5]
254 template <typename IntermediateType, typename ResultType, typename Iterator, typename MapFunctor, typename ReduceFunctor>
startMappedReduced(Iterator begin,Iterator end,MapFunctor mapFunctor,ReduceFunctor reduceFunctor,ReduceOptions options)255 inline ThreadEngineStarter<ResultType> startMappedReduced(Iterator begin, Iterator end,
256                                                            MapFunctor mapFunctor, ReduceFunctor reduceFunctor,
257                                                            ReduceOptions options)
258 {
259     typedef ReduceKernel<ReduceFunctor, ResultType, IntermediateType> Reducer;
260     typedef MappedReducedKernel<ResultType, Iterator, MapFunctor, ReduceFunctor, Reducer> MappedReduceType;
261     return startThreadEngine(new MappedReduceType(begin, end, mapFunctor, reduceFunctor, options));
262 }
263 
264 } // namespace QtConcurrent
265 
266 
267 QT_END_NAMESPACE
268 
269 #endif // QT_NO_CONCURRENT
270 
271 #endif
272