/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://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 https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** 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-3.0.html. ** ****************************************************************************/ #pragma once #include "functiontraits.h" #include "optional.h" #include "utils_global.h" #include #include #include #include #include #include #include #include // hasCallOperator & Co must be outside of any namespace // because of internal compiler error with MSVC2015 Update 2 using testCallOperatorYes = char; using testCallOperatorNo = struct { char foo[2]; }; template static testCallOperatorYes testCallOperator(decltype(&C::operator())); template static testCallOperatorNo testCallOperator(...); template struct hasCallOperator { static const bool value = (sizeof(testCallOperator(nullptr)) == sizeof(testCallOperatorYes)); }; namespace Utils { using StackSizeInBytes = optional; namespace Internal { /* resultType::type Returns the type of results that would be reported by a callable of type F when called through the runAsync methods. I.e. the ResultType in void f(QFutureInterface &fi, ...) ResultType f(...) Returns void if F is not callable, and if F is a callable that does not take a QFutureInterface& as its first parameter and returns void. */ template struct resultType; template struct resultTypeWithArgument; template struct resultTypeTakesArguments; template struct resultTypeIsMemberFunction; template struct resultTypeIsFunctionLike; template struct resultTypeHasCallOperator; template struct resultTypeWithArgument&> { using type = ResultType; }; template struct resultTypeWithArgument { using type = functionResult_t; }; template struct resultTypeTakesArguments : public resultTypeWithArgument::template argument::type> { }; template struct resultTypeTakesArguments { using type = functionResult_t; }; template struct resultTypeIsFunctionLike : public resultTypeTakesArguments::arity > 0)> { }; template struct resultTypeIsMemberFunction : public resultTypeTakesArguments::arity > 1)> { }; template struct resultTypeIsMemberFunction { using type = void; }; template struct resultTypeIsFunctionLike : public resultTypeIsMemberFunction::value> { }; template struct resultTypeHasCallOperator : public resultTypeIsFunctionLike>>::value> { }; template struct resultTypeHasCallOperator : public resultTypeTakesArguments::arity > 0)> { }; template struct resultType : public resultTypeHasCallOperator::value> { }; template struct resultType : public resultType { }; template struct resultType : public resultType { }; template struct resultType : public resultType { }; template struct resultType> : public resultType { }; template struct resultType> : public resultType { }; /* Callable object that wraps a member function pointer with the object it will be called on. */ template class MemberCallable; template class MemberCallable { public: MemberCallable(Result(Obj::* function)(Args...) const, const Obj *obj) : m_function(function), m_obj(obj) { } Result operator()(Args&&... args) const { return ((*m_obj).*m_function)(std::forward(args)...); } private: Result(Obj::* m_function)(Args...) const; const Obj *m_obj; }; template class MemberCallable { public: MemberCallable(Result(Obj::* function)(Args...), Obj *obj) : m_function(function), m_obj(obj) { } Result operator()(Args&&... args) const { return ((*m_obj).*m_function)(std::forward(args)...); } private: Result(Obj::* m_function)(Args...); Obj *m_obj; }; /* Helper functions for runAsync that run in the started thread. */ // void function that does not take QFutureInterface template void runAsyncReturnVoidDispatch(std::true_type, QFutureInterface, Function &&function, Args&&... args) { function(std::forward(args)...); } // non-void function that does not take QFutureInterface template void runAsyncReturnVoidDispatch(std::false_type, QFutureInterface futureInterface, Function &&function, Args&&... args) { futureInterface.reportResult(function(std::forward(args)...)); } // function that takes QFutureInterface template void runAsyncQFutureInterfaceDispatch(std::true_type, QFutureInterface futureInterface, Function &&function, Args&&... args) { function(futureInterface, std::forward(args)...); } // function that does not take QFutureInterface template void runAsyncQFutureInterfaceDispatch(std::false_type, QFutureInterface futureInterface, Function &&function, Args&&... args) { runAsyncReturnVoidDispatch(std::is_void>(), futureInterface, std::forward(function), std::forward(args)...); } // function, function pointer, or other callable object that is no member pointer template >::value> > void runAsyncMemberDispatch(QFutureInterface futureInterface, Function &&function, Args&&... args) { runAsyncQFutureInterfaceDispatch(functionTakesArgument&>(), futureInterface, std::forward(function), std::forward(args)...); } // Function = member function template >::value> > void runAsyncMemberDispatch(QFutureInterface futureInterface, Function &&function, Obj &&obj, Args&&... args) { // Wrap member function with object into callable runAsyncImpl(futureInterface, MemberCallable>(std::forward(function), std::forward(obj)), std::forward(args)...); } // cref to function/callable template void runAsyncImpl(QFutureInterface futureInterface, std::reference_wrapper functionWrapper, Args&&... args) { runAsyncMemberDispatch(futureInterface, functionWrapper.get(), std::forward(args)...); } // function/callable, no cref template void runAsyncImpl(QFutureInterface futureInterface, Function &&function, Args&&... args) { runAsyncMemberDispatch(futureInterface, std::forward(function), std::forward(args)...); } /* AsyncJob is a QRunnable that wraps a function with the arguments that are passed to it when it is run in a thread. */ template std::decay_t decayCopy(T&& v) { return std::forward(v); } template class AsyncJob : public QRunnable { public: AsyncJob(Function &&function, Args&&... args) // decay copy like std::thread : data(decayCopy(std::forward(function)), decayCopy(std::forward(args))...) { // we need to report it as started even though it isn't yet, because someone might // call waitForFinished on the future, which does _not_ block if the future is not started futureInterface.setRunnable(this); futureInterface.reportStarted(); } ~AsyncJob() override { // QThreadPool can delete runnables even if they were never run (e.g. QThreadPool::clear). // Since we reported them as started, we make sure that we always report them as finished. // reportFinished only actually sends the signal if it wasn't already finished. futureInterface.reportFinished(); } QFuture future() { return futureInterface.future(); } void run() override { if (priority != QThread::InheritPriority) if (QThread *thread = QThread::currentThread()) if (thread != qApp->thread()) thread->setPriority(priority); if (futureInterface.isCanceled()) { futureInterface.reportFinished(); return; } runHelper(std::make_index_sequence::value>()); } void setThreadPool(QThreadPool *pool) { futureInterface.setThreadPool(pool); } void setThreadPriority(QThread::Priority p) { priority = p; } private: using Data = std::tuple, std::decay_t...>; template void runHelper(std::index_sequence) { // invalidates data, which is moved into the call runAsyncImpl(futureInterface, std::move(std::get(data))...); if (futureInterface.isPaused()) futureInterface.waitForResume(); futureInterface.reportFinished(); } Data data; QFutureInterface futureInterface; QThread::Priority priority = QThread::InheritPriority; }; class QTCREATOR_UTILS_EXPORT RunnableThread : public QThread { public: explicit RunnableThread(QRunnable *runnable, QObject *parent = nullptr); protected: void run() override; private: QRunnable *m_runnable; }; template::type> QFuture runAsync_internal(QThreadPool *pool, StackSizeInBytes stackSize, QThread::Priority priority, Function &&function, Args &&... args) { Q_ASSERT(!(pool && stackSize)); // stack size cannot be changed once a thread is started auto job = new Internal::AsyncJob (std::forward(function), std::forward(args)...); job->setThreadPriority(priority); QFuture future = job->future(); if (pool) { job->setThreadPool(pool); pool->start(job); } else { auto thread = new Internal::RunnableThread(job); if (stackSize) thread->setStackSize(stackSize.value()); thread->moveToThread(qApp->thread()); // make sure thread gets deleteLater on main thread QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater); thread->start(priority); } return future; } } // Internal /*! The interface of \c {runAsync} is similar to the std::thread constructor and \c {std::invoke}. The \a function argument can be a member function, an object with \c {operator()} (with no overloads), a \c {std::function}, lambda, function pointer or function reference. The \a args are passed to the function call after they are copied/moved to the thread. The \a function can take a \c {QFutureInterface&} as its first argument, followed by other custom arguments which need to be passed to this function. If it does not take a \c {QFutureInterface&} as its first argument and its return type is not void, the function call's result is reported to the QFuture. If \a function is a (non-static) member function, the first argument in \a args is expected to be the object that the function is called on. If a thread \a pool is given, the function is run there. Otherwise a new, independent thread is started. \sa std::thread \sa std::invoke \sa QThreadPool \sa QThread::Priority */ template ::type> QFuture runAsync(QThreadPool *pool, QThread::Priority priority, Function &&function, Args&&... args) { return Internal::runAsync_internal(pool, StackSizeInBytes(), priority, std::forward(function), std::forward(args)...); } /*! Runs \a function with \a args in a new thread with given thread \a priority. \sa runAsync(QThreadPool*,QThread::Priority,Function&&,Args&&...) \sa QThread::Priority */ template ::type> QFuture runAsync(QThread::Priority priority, Function &&function, Args&&... args) { return runAsync(static_cast(nullptr), priority, std::forward(function), std::forward(args)...); } /*! Runs \a function with \a args in a new thread with given thread \a stackSize and thread priority QThread::InheritPriority . \sa runAsync(QThreadPool*,QThread::Priority,Function&&,Args&&...) \sa QThread::Priority \sa QThread::setStackSize */ template::type> QFuture runAsync(Utils::StackSizeInBytes stackSize, Function &&function, Args &&... args) { return Internal::runAsync_internal(static_cast(nullptr), stackSize, QThread::InheritPriority, std::forward(function), std::forward(args)...); } /*! Runs \a function with \a args in a new thread with given thread \a stackSize and given thread \a priority. \sa runAsync(QThreadPool*,QThread::Priority,Function&&,Args&&...) \sa QThread::Priority \sa QThread::setStackSize */ template::type> QFuture runAsync(Utils::StackSizeInBytes stackSize, QThread::Priority priority, Function &&function, Args &&... args) { return Internal::runAsync_internal(static_cast(nullptr), stackSize, priority, std::forward(function), std::forward(args)...); } /*! Runs \a function with \a args in a new thread with thread priority QThread::InheritPriority. \sa runAsync(QThreadPool*,QThread::Priority,Function&&,Args&&...) \sa QThread::Priority */ template , QThreadPool>::value && !std::is_same, QThread::Priority>::value >, typename ResultType = typename Internal::resultType::type> QFuture runAsync(Function &&function, Args&&... args) { return runAsync(static_cast(nullptr), QThread::InheritPriority, std::forward(function), std::forward(args)...); } /*! Runs \a function with \a args in a thread \a pool with thread priority QThread::InheritPriority. \sa runAsync(QThreadPool*,QThread::Priority,Function&&,Args&&...) \sa QThread::Priority */ template , QThread::Priority>::value>, typename ResultType = typename Internal::resultType::type> QFuture runAsync(QThreadPool *pool, Function &&function, Args&&... args) { return runAsync(pool, QThread::InheritPriority, std::forward(function), std::forward(args)...); } /*! Adds a handler for when a result is ready. This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions or create a QFutureWatcher already for other reasons. */ template const QFuture &onResultReady(const QFuture &future, R *receiver, void(R::*member)(const T &)) { auto watcher = new QFutureWatcher(); QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, receiver, [receiver, member, watcher](int index) { (receiver->*member)(watcher->future().resultAt(index)); }); watcher->setFuture(future); return future; } /*! Adds a handler for when a result is ready. The guard object determines the lifetime of the connection. This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions or create a QFutureWatcher already for other reasons. */ template const QFuture &onResultReady(const QFuture &future, QObject *guard, Function f) { auto watcher = new QFutureWatcher(); QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, guard, [f, watcher](int index) { f(watcher->future().resultAt(index)); }); watcher->setFuture(future); return future; } /*! Adds a handler for when a result is ready. This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions or create a QFutureWatcher already for other reasons. */ template const QFuture &onResultReady(const QFuture &future, Function f) { auto watcher = new QFutureWatcher(); QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, [f, watcher](int index) { f(watcher->future().resultAt(index)); }); watcher->setFuture(future); return future; } /*! Adds a handler for when the future is finished. This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions or create a QFutureWatcher already for other reasons. */ template const QFuture &onFinished(const QFuture &future, R *receiver, void (R::*member)(const QFuture &)) { auto watcher = new QFutureWatcher(); QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); QObject::connect(watcher, &QFutureWatcherBase::finished, receiver, [receiver, member, watcher]() { (receiver->*member)(watcher->future()); }); watcher->setFuture(future); return future; } /*! Adds a handler for when the future is finished. The guard object determines the lifetime of the connection. This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions or create a QFutureWatcher already for other reasons. */ template const QFuture &onFinished(const QFuture &future, QObject *guard, Function f) { auto watcher = new QFutureWatcher(); QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); QObject::connect(watcher, &QFutureWatcherBase::finished, guard, [f, watcher]() { f(watcher->future()); }); watcher->setFuture(future); return future; } /*! Adds a handler for when the future is finished. This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions or create a QFutureWatcher already for other reasons. */ template const QFuture &onFinished(const QFuture &future, Function f) { auto watcher = new QFutureWatcher(); QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); QObject::connect(watcher, &QFutureWatcherBase::finished, [f, watcher]() { f(watcher->future()); }); watcher->setFuture(future); return future; } } // namespace Utils