/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing ** ** This file is part of Qt Creator. ** ** 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 http://www.qt.io/terms-conditions. For further information ** use the contact form at http://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 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #ifndef RUNEXTENSIONS_H #define RUNEXTENSIONS_H #include "qtcassert.h" #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace QtConcurrent { template class StoredInterfaceFunctionCall0 : public QRunnable { public: StoredInterfaceFunctionCall0(const FunctionPointer &fn) : fn(fn) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; }; template class StoredInterfaceMemberFunctionCall0 : public QRunnable { public: StoredInterfaceMemberFunctionCall0(void (Class::*fn)(QFutureInterface &), Class *object) : fn(fn), object(object) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; }; template class StoredInterfaceFunctionCall1 : public QRunnable { public: StoredInterfaceFunctionCall1(void (fn)(QFutureInterface &, Arg1), const Arg1 &arg1) : fn(fn), arg1(arg1) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Arg1 arg1; }; template class StoredInterfaceMemberFunctionCall1 : public QRunnable { public: StoredInterfaceMemberFunctionCall1(void (Class::*fn)(QFutureInterface &, Arg1), Class *object, const Arg1 &arg1) : fn(fn), object(object), arg1(arg1) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; }; template class StoredInterfaceFunctionCall2 : public QRunnable { public: StoredInterfaceFunctionCall2(void (fn)(QFutureInterface &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2) : fn(fn), arg1(arg1), arg2(arg2) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; }; template class StoredInterfaceMemberFunctionCall2 : public QRunnable { public: StoredInterfaceMemberFunctionCall2(void (Class::*fn)(QFutureInterface &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2) : fn(fn), object(object), arg1(arg1), arg2(arg2) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; }; template class StoredInterfaceFunctionCall3 : public QRunnable { public: StoredInterfaceFunctionCall3(void (fn)(QFutureInterface &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2, arg3); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; Arg3 arg3; }; template class StoredInterfaceMemberFunctionCall3 : public QRunnable { public: StoredInterfaceMemberFunctionCall3(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2, arg3); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; Arg3 arg3; }; template class StoredInterfaceFunctionCall4 : public QRunnable { public: StoredInterfaceFunctionCall4(void (fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2, arg3, arg4); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; }; template class StoredInterfaceMemberFunctionCall4 : public QRunnable { public: StoredInterfaceMemberFunctionCall4(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2, arg3, arg4); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; }; template class StoredInterfaceFunctionCall5 : public QRunnable { public: StoredInterfaceFunctionCall5(void (fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { fn(futureInterface, arg1, arg2, arg3, arg4, arg5); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; }; template class StoredInterfaceMemberFunctionCall5 : public QRunnable { public: StoredInterfaceMemberFunctionCall5(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { } QFuture start() { futureInterface.reportStarted(); QFuture future = futureInterface.future(); QThreadPool::globalInstance()->start(this); return future; } void run() { (object->*fn)(futureInterface, arg1, arg2, arg3, arg4, arg5); futureInterface.reportFinished(); } private: QFutureInterface futureInterface; FunctionPointer fn; Class *object; Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5; }; template QFuture run(void (*functionPointer)(QFutureInterface &)) { return (new StoredInterfaceFunctionCall0 &)>(functionPointer))->start(); } template QFuture run(void (*functionPointer)(QFutureInterface &, Arg1), const Arg1 &arg1) { return (new StoredInterfaceFunctionCall1 &, Arg1), Arg1>(functionPointer, arg1))->start(); } template QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2), const Arg1 &arg1, const Arg2 &arg2) { return (new StoredInterfaceFunctionCall2 &, Arg1, Arg2), Arg1, Arg2>(functionPointer, arg1, arg2))->start(); } template QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2, Arg3), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { return (new StoredInterfaceFunctionCall3 &, Arg1, Arg2, Arg3), Arg1, Arg2, Arg3>(functionPointer, arg1, arg2, arg3))->start(); } template QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { return (new StoredInterfaceFunctionCall4 &, Arg1, Arg2, Arg3, Arg4), Arg1, Arg2, Arg3, Arg4>(functionPointer, arg1, arg2, arg3, arg4))->start(); } template QFuture run(void (*functionPointer)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4, Arg5), const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { return (new StoredInterfaceFunctionCall5 &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1, Arg2, Arg3, Arg4, Arg5>(functionPointer, arg1, arg2, arg3, arg4, arg5))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &), Class *object) { return (new StoredInterfaceMemberFunctionCall0 &), Class>(fn, object))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &, Arg1), Class *object, Arg1 arg1) { return (new StoredInterfaceMemberFunctionCall1 &, Arg1), Class, Arg1>(fn, object, arg1))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &, Arg1, Arg2), Class *object, const Arg1 &arg1, const Arg2 &arg2) { return (new StoredInterfaceMemberFunctionCall2 &, Arg1, Arg2), Class, Arg1, Arg2>(fn, object, arg1, arg2))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3) { return (new StoredInterfaceMemberFunctionCall3 &, Arg1, Arg2, Arg3), Class, Arg1, Arg2, Arg3>(fn, object, arg1, arg2, arg3))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4) { return (new StoredInterfaceMemberFunctionCall4 &, Arg1, Arg2, Arg3, Arg4), Class, Arg1, Arg2, Arg3, Arg4>(fn, object, arg1, arg2, arg3, arg4))->start(); } template QFuture run(void (Class::*fn)(QFutureInterface &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, const Arg1 &arg1, const Arg2 &arg2, const Arg3 &arg3, const Arg4 &arg4, const Arg5 &arg5) { return (new StoredInterfaceMemberFunctionCall5 &, Arg1, Arg2, Arg3, Arg4, Arg5), Class, Arg1, Arg2, Arg3, Arg4, Arg5>(fn, object, arg1, arg2, arg3, arg4, arg5))->start(); } template QFuture run(const std::function &)> &fn) { return (new StoredInterfaceFunctionCall0 &)>>(fn))->start(); } } // namespace QtConcurrent QT_END_NAMESPACE namespace Utils { template typename std::vector>::iterator waitForAny(std::vector> &futures) { // Wait for any future to have a result ready. // Unfortunately we have to do that in a busy loop because future doesn't have a feature to // wait for any of a set of futures (yet? possibly when_any in C++17). auto end = futures.end(); QTC_ASSERT(!futures.empty(), return end); auto futureIterator = futures.begin(); forever { if (futureIterator->wait_for(std::chrono::duration::zero()) == std::future_status::ready) return futureIterator; ++futureIterator; if (futureIterator == end) futureIterator = futures.begin(); } } namespace Internal { template void swapErase(std::vector &vec, typename std::vector::iterator it) { // efficient erasing by swapping with back element *it = std::move(vec.back()); vec.pop_back(); } template void reduceOne(QFutureInterface &futureInterface, std::vector> &futures, State &state, const ReduceFunction &reduce) { auto futureIterator = waitForAny(futures); if (futureIterator != futures.end()) { reduce(futureInterface, state, futureIterator->get()); swapErase(futures, futureIterator); } } // This together with reduceOne can be replaced by std::transformReduce (parallelism TS) // when that becomes widely available in C++ implementations template void mapReduceLoop(QFutureInterface &futureInterface, const Container &container, const MapFunction &map, State &state, const ReduceFunction &reduce) { const unsigned MAX_THREADS = std::thread::hardware_concurrency(); using MapResult = typename std::result_of,typename Container::value_type)>::type; std::vector> futures; futures.reserve(MAX_THREADS); auto fileIterator = container.begin(); auto end = container.end(); while (!futureInterface.isCanceled() && (fileIterator != end || futures.size() != 0)) { if (futures.size() >= MAX_THREADS || fileIterator == end) { // We don't want to start a new thread (yet), so try to find a future that is ready and // handle its result. reduceOne(futureInterface, futures, state, reduce); } else { // start a new thread futures.push_back(std::async(std::launch::async, map, futureInterface, *fileIterator)); ++fileIterator; } } } template void blockingMapReduce(QFutureInterface futureInterface, const Container &container, const InitFunction &init, const MapFunction &map, const ReduceFunction &reduce, const CleanUpFunction &cleanup) { auto state = init(futureInterface); mapReduceLoop(futureInterface, container, map, state, reduce); cleanup(futureInterface, state); if (futureInterface.isPaused()) futureInterface.waitForResume(); futureInterface.reportFinished(); } template void runAsyncImpl(QFutureInterface futureInterface, const Function &function, const Args&... args) { function(futureInterface, args...); if (futureInterface.isPaused()) futureInterface.waitForResume(); futureInterface.reportFinished(); } } // Internal template QFuture mapReduce(std::reference_wrapper containerWrapper, const InitFunction &init, const MapFunction &map, const ReduceFunction &reduce, const CleanUpFunction &cleanup) { auto fi = QFutureInterface(); QFuture future = fi.future(); fi.reportStarted(); std::thread(Internal::blockingMapReduce, fi, containerWrapper, init, map, reduce, cleanup).detach(); return future; } template QFuture mapReduce(const Container &container, const InitFunction &init, const MapFunction &map, const ReduceFunction &reduce, const CleanUpFunction &cleanup) { auto fi = QFutureInterface(); QFuture future = fi.future(); std::thread(Internal::blockingMapReduce, fi, container, init, map, reduce, cleanup).detach(); return future; } template QFuture runAsync(Function &&function, Args&&... args) { QFutureInterface futureInterface; futureInterface.reportStarted(); std::thread(Internal::runAsyncImpl, futureInterface, std::forward(function), std::forward(args)...).detach(); return futureInterface.future(); } } // Utils #endif // RUNEXTENSIONS_H