/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtConcurrent module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QTCONCURRENT_MAPKERNEL_H #define QTCONCURRENT_MAPKERNEL_H #include #if !defined(QT_NO_CONCURRENT) || defined (Q_CLANG_QDOC) #include #include #include QT_BEGIN_NAMESPACE namespace QtConcurrent { // map kernel, works with both parallel-for and parallel-while template class MapKernel : public IterateKernel { MapFunctor map; public: typedef void ReturnType; template MapKernel(QThreadPool *pool, Iterator begin, Iterator end, F &&_map) : IterateKernel(pool, begin, end), map(std::forward(_map)) { } bool runIteration(Iterator it, int, void *) override { std::invoke(map, *it); return false; } bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, void *) override { Iterator it = sequenceBeginIterator; std::advance(it, beginIndex); for (int i = beginIndex; i < endIndex; ++i) { runIteration(it, i, nullptr); std::advance(it, 1); } return false; } }; template >> class MappedReducedKernel : public IterateKernel { ReducedResultType &reducedResult; MapFunctor map; ReduceFunctor reduce; Reducer reducer; using IntermediateResultsType = QtPrivate::MapResultType; public: typedef ReducedResultType ReturnType; template MappedReducedKernel(QThreadPool *pool, Iterator begin, Iterator end, F1 &&_map, F2 &&_reduce, ReduceOptions reduceOptions) : IterateKernel(pool, begin, end), reducedResult(this->defaultValue.value), map(std::forward(_map)), reduce(std::forward(_reduce)), reducer(pool, reduceOptions) { } template MappedReducedKernel(QThreadPool *pool, Iterator begin, Iterator end, F1 &&_map, F2 &&_reduce, ReducedResultType &&initialValue, ReduceOptions reduceOptions) : IterateKernel(pool, begin, end, std::forward(initialValue)), reducedResult(this->defaultValue.value), map(std::forward(_map)), reduce(std::forward(_reduce)), reducer(pool, reduceOptions) { } bool runIteration(Iterator it, int index, ReducedResultType *) override { IntermediateResults results; results.begin = index; results.end = index + 1; results.vector.append(std::invoke(map, *it)); reducer.runReduce(reduce, reducedResult, results); return false; } bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, ReducedResultType *) override { IntermediateResults results; results.begin = beginIndex; results.end = endIndex; results.vector.reserve(endIndex - beginIndex); Iterator it = sequenceBeginIterator; std::advance(it, beginIndex); for (int i = beginIndex; i < endIndex; ++i) { results.vector.append(std::invoke(map, *it)); std::advance(it, 1); } reducer.runReduce(reduce, reducedResult, results); return false; } void finish() override { reducer.finish(reduce, reducedResult); } bool shouldThrottleThread() override { return IterateKernel::shouldThrottleThread() || reducer.shouldThrottle(); } bool shouldStartThread() override { return IterateKernel::shouldStartThread() && reducer.shouldStartThread(); } typedef ReducedResultType ResultType; ReducedResultType *result() override { return &reducedResult; } }; template class MappedEachKernel : public IterateKernel> { MapFunctor map; using T = QtPrivate::MapResultType; public: template MappedEachKernel(QThreadPool *pool, Iterator begin, Iterator end, F &&_map) : IterateKernel(pool, begin, end), map(std::forward(_map)) { } bool runIteration(Iterator it, int, T *result) override { *result = std::invoke(map, *it); return true; } bool runIterations(Iterator sequenceBeginIterator, int beginIndex, int endIndex, T *results) override { Iterator it = sequenceBeginIterator; std::advance(it, beginIndex); for (int i = beginIndex; i < endIndex; ++i) { runIteration(it, i, results + (i - beginIndex)); std::advance(it, 1); } return true; } }; //! [qtconcurrentmapkernel-1] template inline ThreadEngineStarter startMap(QThreadPool *pool, Iterator begin, Iterator end, Functor &&functor) { return startThreadEngine(new MapKernel>( pool, begin, end, std::forward(functor))); } //! [qtconcurrentmapkernel-2] template inline ThreadEngineStarter startMapped(QThreadPool *pool, Iterator begin, Iterator end, Functor &&functor) { return startThreadEngine(new MappedEachKernel>( pool, begin, end, std::forward(functor))); } /* The SequnceHolder class is used to hold a reference to the sequence we are working on. */ template struct SequenceHolder1 : private QtPrivate::SequenceHolder, public Base { template SequenceHolder1(QThreadPool *pool, S &&_sequence, F &&functor) : QtPrivate::SequenceHolder(std::forward(_sequence)), Base(pool, this->sequence.cbegin(), this->sequence.cend(), std::forward(functor)) { } void finish() override { Base::finish(); // Clear the sequence to make sure all temporaries are destroyed // before finished is signaled. this->sequence = Sequence(); } }; //! [qtconcurrentmapkernel-3] template inline ThreadEngineStarter startMapped(QThreadPool *pool, Sequence &&sequence, Functor &&functor) { using DecayedSequence = std::decay_t; using DecayedFunctor = std::decay_t; using SequenceHolderType = SequenceHolder1< DecayedSequence, MappedEachKernel, DecayedFunctor>; return startThreadEngine(new SequenceHolderType(pool, std::forward(sequence), std::forward(functor))); } //! [qtconcurrentmapkernel-4] template inline ThreadEngineStarter startMappedReduced(QThreadPool *pool, Sequence &&sequence, MapFunctor &&mapFunctor, ReduceFunctor &&reduceFunctor, ReduceOptions options) { using DecayedSequence = std::decay_t; using DecayedMapFunctor = std::decay_t; using DecayedReduceFunctor = std::decay_t; using Iterator = typename DecayedSequence::const_iterator; using Reducer = ReduceKernel; using MappedReduceType = MappedReducedKernel; using SequenceHolderType = SequenceHolder2; return startThreadEngine(new SequenceHolderType(pool, std::forward(sequence), std::forward(mapFunctor), std::forward(reduceFunctor), options)); } //! [qtconcurrentmapkernel-5] template inline ThreadEngineStarter startMappedReduced(QThreadPool *pool, Iterator begin, Iterator end, MapFunctor &&mapFunctor, ReduceFunctor &&reduceFunctor, ReduceOptions options) { using Reducer = ReduceKernel, std::decay_t, IntermediateType>; using MappedReduceType = MappedReducedKernel, std::decay_t, Reducer>; return startThreadEngine(new MappedReduceType(pool, begin, end, std::forward(mapFunctor), std::forward(reduceFunctor), options)); } //! [qtconcurrentmapkernel-6] template inline ThreadEngineStarter startMappedReduced(QThreadPool *pool, Sequence &&sequence, MapFunctor &&mapFunctor, ReduceFunctor &&reduceFunctor, ResultType &&initialValue, ReduceOptions options) { using DecayedSequence = std::decay_t; using DecayedMapFunctor = std::decay_t; using DecayedReduceFunctor = std::decay_t; using Iterator = typename DecayedSequence::const_iterator; using Reducer = ReduceKernel; using MappedReduceType = MappedReducedKernel; using SequenceHolderType = SequenceHolder2; return startThreadEngine( new SequenceHolderType(pool, std::forward(sequence), std::forward(mapFunctor), std::forward(reduceFunctor), std::forward(initialValue), options)); } //! [qtconcurrentmapkernel-7] template inline ThreadEngineStarter startMappedReduced(QThreadPool *pool, Iterator begin, Iterator end, MapFunctor &&mapFunctor, ReduceFunctor &&reduceFunctor, ResultType &&initialValue, ReduceOptions options) { using Reducer = ReduceKernel, ResultType, IntermediateType>; using MappedReduceType = MappedReducedKernel, std::decay_t, Reducer>; return startThreadEngine(new MappedReduceType(pool, begin, end, std::forward(mapFunctor), std::forward(reduceFunctor), std::forward(initialValue), options)); } } // namespace QtConcurrent QT_END_NAMESPACE #endif // QT_NO_CONCURRENT #endif