/**************************************************************************** ** ** 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_FILTERKERNEL_H #define QTCONCURRENT_FILTERKERNEL_H #include #if !defined(QT_NO_CONCURRENT) || defined (Q_CLANG_QDOC) #include #include #include QT_BEGIN_NAMESPACE namespace QtConcurrent { template struct qValueType { typedef typename T::value_type value_type; }; template struct qValueType { typedef T value_type; }; template struct qValueType { typedef T value_type; }; // Implementation of filter template class FilterKernel : public IterateKernel { typedef ReduceKernel Reducer; typedef IterateKernel IterateKernelType; typedef void T; Sequence reducedResult; Sequence &sequence; KeepFunctor keep; ReduceFunctor reduce; Reducer reducer; public: template FilterKernel(QThreadPool *pool, Sequence &_sequence, Keep &&_keep, Reduce &&_reduce) : IterateKernelType(pool, const_cast(_sequence).begin(), const_cast(_sequence).end()), reducedResult(), sequence(_sequence), keep(std::forward(_keep)), reduce(std::forward(_reduce)), reducer(pool, OrderedReduce) { } bool runIteration(typename Sequence::const_iterator it, int index, T *) override { IntermediateResults results; results.begin = index; results.end = index + 1; if (std::invoke(keep, *it)) results.vector.append(*it); reducer.runReduce(reduce, reducedResult, results); return false; } bool runIterations(typename Sequence::const_iterator sequenceBeginIterator, int begin, int end, T *) override { IntermediateResults results; results.begin = begin; results.end = end; results.vector.reserve(end - begin); typename Sequence::const_iterator it = sequenceBeginIterator; std::advance(it, begin); for (int i = begin; i < end; ++i) { if (std::invoke(keep, *it)) results.vector.append(*it); std::advance(it, 1); } reducer.runReduce(reduce, reducedResult, results); return false; } void finish() override { reducer.finish(reduce, reducedResult); sequence = std::move(reducedResult); } inline bool shouldThrottleThread() override { return IterateKernelType::shouldThrottleThread() || reducer.shouldThrottle(); } inline bool shouldStartThread() override { return IterateKernelType::shouldStartThread() && reducer.shouldStartThread(); } typedef void ReturnType; typedef void ResultType; }; // Implementation of filter-reduce template ::value_type> > class FilteredReducedKernel : public IterateKernel { ReducedResultType &reducedResult; KeepFunctor keep; ReduceFunctor reduce; Reducer reducer; typedef IterateKernel IterateKernelType; public: template FilteredReducedKernel(QThreadPool *pool, Iterator begin, Iterator end, Keep &&_keep, Reduce &&_reduce, ReduceOptions reduceOption) : IterateKernelType(pool, begin, end), reducedResult(this->defaultValue.value), keep(std::forward(_keep)), reduce(std::forward(_reduce)), reducer(pool, reduceOption) { } template FilteredReducedKernel(QThreadPool *pool, Iterator begin, Iterator end, Keep &&_keep, Reduce &&_reduce, ReducedResultType &&initialValue, ReduceOptions reduceOption) : IterateKernelType(pool, begin, end, std::forward(initialValue)), reducedResult(this->defaultValue.value), keep(std::forward(_keep)), reduce(std::forward(_reduce)), reducer(pool, reduceOption) { } bool runIteration(Iterator it, int index, ReducedResultType *) override { IntermediateResults::value_type> results; results.begin = index; results.end = index + 1; if (std::invoke(keep, *it)) results.vector.append(*it); reducer.runReduce(reduce, reducedResult, results); return false; } bool runIterations(Iterator sequenceBeginIterator, int begin, int end, ReducedResultType *) override { IntermediateResults::value_type> results; results.begin = begin; results.end = end; results.vector.reserve(end - begin); Iterator it = sequenceBeginIterator; std::advance(it, begin); for (int i = begin; i < end; ++i) { if (std::invoke(keep, *it)) results.vector.append(*it); std::advance(it, 1); } reducer.runReduce(reduce, reducedResult, results); return false; } void finish() override { reducer.finish(reduce, reducedResult); } inline bool shouldThrottleThread() override { return IterateKernelType::shouldThrottleThread() || reducer.shouldThrottle(); } inline bool shouldStartThread() override { return IterateKernelType::shouldStartThread() && reducer.shouldStartThread(); } typedef ReducedResultType ReturnType; typedef ReducedResultType ResultType; ReducedResultType *result() override { return &reducedResult; } }; // Implementation of filter that reports individual results via QFutureInterface template class FilteredEachKernel : public IterateKernel::value_type> { typedef typename qValueType::value_type T; typedef IterateKernel IterateKernelType; KeepFunctor keep; public: typedef T ReturnType; typedef T ResultType; template FilteredEachKernel(QThreadPool *pool, Iterator begin, Iterator end, Keep &&_keep) : IterateKernelType(pool, begin, end), keep(std::forward(_keep)) { } void start() override { if (this->futureInterface) this->futureInterface->setFilterMode(true); IterateKernelType::start(); } bool runIteration(Iterator it, int index, T *) override { if (std::invoke(keep, *it)) this->reportResult(&(*it), index); else this->reportResult(nullptr, index); return false; } bool runIterations(Iterator sequenceBeginIterator, int begin, int end, T *) override { const int count = end - begin; IntermediateResults::value_type> results; results.begin = begin; results.end = end; results.vector.reserve(count); Iterator it = sequenceBeginIterator; std::advance(it, begin); for (int i = begin; i < end; ++i) { if (std::invoke(keep, *it)) results.vector.append(*it); std::advance(it, 1); } this->reportResults(results.vector, begin, count); return false; } }; //! [QtConcurrent-2] template inline ThreadEngineStarter::value_type> startFiltered(QThreadPool *pool, Iterator begin, Iterator end, KeepFunctor &&functor) { return startThreadEngine(new FilteredEachKernel> (pool, begin, end, std::forward(functor))); } //! [QtConcurrent-3] template inline decltype(auto) startFiltered(QThreadPool *pool, Sequence &&sequence, KeepFunctor &&functor) { using DecayedSequence = std::decay_t; using DecayedFunctor = std::decay_t; using SequenceHolderType = SequenceHolder1, DecayedFunctor>; return startThreadEngine(new SequenceHolderType(pool, std::forward(sequence), std::forward(functor))); } //! [QtConcurrent-4] template inline ThreadEngineStarter startFilteredReduced(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::value_type>; using FilteredReduceType = FilteredReducedKernel; using SequenceHolderType = SequenceHolder2; return startThreadEngine(new SequenceHolderType(pool, std::forward(sequence), std::forward(mapFunctor), std::forward(reduceFunctor), options)); } //! [QtConcurrent-5] template inline ThreadEngineStarter startFilteredReduced(QThreadPool *pool, Iterator begin, Iterator end, MapFunctor &&mapFunctor, ReduceFunctor &&reduceFunctor, ReduceOptions options) { using Reducer = ReduceKernel, ResultType, typename qValueType::value_type>; using FilteredReduceType = FilteredReducedKernel, std::decay_t, Reducer>; return startThreadEngine( new FilteredReduceType(pool, begin, end, std::forward(mapFunctor), std::forward(reduceFunctor), options)); } // Repeat the two functions above, but now with an initial value! //! [QtConcurrent-6] template inline ThreadEngineStarter startFilteredReduced(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::value_type>; using FilteredReduceType = FilteredReducedKernel; using SequenceHolderType = SequenceHolder2; return startThreadEngine(new SequenceHolderType( pool, std::forward(sequence), std::forward(mapFunctor), std::forward(reduceFunctor), std::forward(initialValue), options)); } //! [QtConcurrent-7] template inline ThreadEngineStarter startFilteredReduced(QThreadPool *pool, Iterator begin, Iterator end, MapFunctor &&mapFunctor, ReduceFunctor &&reduceFunctor, ResultType &&initialValue, ReduceOptions options) { using Reducer = ReduceKernel, ResultType, typename qValueType::value_type>; using FilteredReduceType = FilteredReducedKernel, std::decay_t, Reducer>; return startThreadEngine( new FilteredReduceType(pool, begin, end, std::forward(mapFunctor), std::forward(reduceFunctor), std::forward(initialValue), options)); } } // namespace QtConcurrent QT_END_NAMESPACE #endif // QT_NO_CONCURRENT #endif