From 5e580299e342bd77fc7479bbfd235f4446d7f05b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Mon, 18 May 2015 15:20:35 +0200 Subject: KAsync has moved to it's own kasync.git repository --- async/src/CMakeLists.txt | 63 ---- async/src/async.cpp | 148 -------- async/src/async.h | 874 ----------------------------------------------- async/src/async_impl.h | 81 ----- async/src/debug.cpp | 75 ---- async/src/debug.h | 82 ----- async/src/future.cpp | 158 --------- async/src/future.h | 257 -------------- 8 files changed, 1738 deletions(-) delete mode 100644 async/src/CMakeLists.txt delete mode 100644 async/src/async.cpp delete mode 100644 async/src/async.h delete mode 100644 async/src/async_impl.h delete mode 100644 async/src/debug.cpp delete mode 100644 async/src/debug.h delete mode 100644 async/src/future.cpp delete mode 100644 async/src/future.h (limited to 'async/src') diff --git a/async/src/CMakeLists.txt b/async/src/CMakeLists.txt deleted file mode 100644 index 05d08b6..0000000 --- a/async/src/CMakeLists.txt +++ /dev/null @@ -1,63 +0,0 @@ -set(kasync_SRCS - async.cpp - future.cpp - debug.cpp -) - -set(kasync_priv_HEADERS - async_impl.h - debug.h -) - -ecm_generate_headers(kasync_HEADERS - HEADER_NAMES - Async - Future -) - - -add_library(KF5Async ${kasync_SRCS}) -add_library(KF5::Async ALIAS KF5Async) - -generate_export_header(KF5Async BASE_NAME kasync) - -target_include_directories(KF5Async INTERFACE "$") -target_include_directories(KF5Async PUBLIC "$") - -target_link_libraries(KF5Async - PUBLIC - Qt5::Core -) -if (WITH_KJOB) - target_link_libraries(KF5Async PUBLIC KF5::CoreAddons) -endif () - - -set_target_properties(KF5Async PROPERTIES - VERSION ${KASYNC_VERSION_STRING} - SOVERSION ${KASYNC_SOVERSION} - EXPORT_NAME KAsync -) - -ecm_generate_pri_file(BASE_NAME KAsync - LIB_NAME KF5Async - FILENAME_VAR PRI_FILENAME -) - -install(TARGETS - KF5Async - EXPORT KF5AsyncTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS} -) - -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/kasync_export.h - ${kasync_HEADERS} - ${kasync_priv_HEADERS} - DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/Async - COMPONENT Devel -) - -install(FILES - ${PRI_FILENAME} - DESTINATION ${ECM_MKSPECS_INSTALL_DIR} -) diff --git a/async/src/async.cpp b/async/src/async.cpp deleted file mode 100644 index c57c9ad..0000000 --- a/async/src/async.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2014 Daniel Vrátil - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library. If not, see . - */ - -#include "async.h" - -#include -#include -#include -#include - -using namespace KAsync; - -Private::Execution::Execution(const Private::ExecutorBasePtr &executor) - : executor(executor) - , resultBase(nullptr) - , isRunning(false) - , isFinished(false) -{ -} - -Private::Execution::~Execution() -{ - if (resultBase) { - resultBase->releaseExecution(); - delete resultBase; - } - prevExecution.reset(); -} - -void Private::Execution::setFinished() -{ - isFinished = true; - //executor.clear(); -#ifndef QT_NO_DEBUG - if (tracer) { - delete tracer; - } -#endif -} - -void Private::Execution::releaseFuture() -{ - resultBase = 0; -} - -bool Private::Execution::errorWasHandled() const -{ - Execution *exec = const_cast(this); - while (exec) { - if (exec->executor->hasErrorFunc()) { - return true; - } - exec = exec->prevExecution.data(); - } - return false; -} - - - - - -Private::ExecutorBase::ExecutorBase(const ExecutorBasePtr &parent) - : mPrev(parent) -{ -} - -Private::ExecutorBase::~ExecutorBase() -{ -} - - - - -JobBase::JobBase(const Private::ExecutorBasePtr &executor) - : mExecutor(executor) -{ -} - -JobBase::~JobBase() -{ -} - -static void asyncWhile(const std::function)> &body, const std::function &completionHandler) { - body([body, completionHandler](bool complete) { - if (complete) { - completionHandler(); - } else { - asyncWhile(body, completionHandler); - } - }); -} - -Job KAsync::dowhile(Condition condition, ThenTask body) -{ - return KAsync::start([body, condition](KAsync::Future &future) { - asyncWhile([condition, body](std::function whileCallback) { - KAsync::start(body).then([whileCallback, condition]() { - whileCallback(!condition()); - }).exec(); - }, - [&future]() { //while complete - future.setFinished(); - }); - }); -} - -Job KAsync::dowhile(ThenTask body) -{ - return KAsync::start([body](KAsync::Future &future) { - asyncWhile([body](std::function whileCallback) { - KAsync::start(body).then([whileCallback](bool result) { - whileCallback(!result); - //FIXME this return value is only required because .then doesn't work - return true; - }).exec(); - }, - [&future]() { //while complete - future.setFinished(); - }); - }); -} - -Job KAsync::wait(int delay) -{ - auto timer = QSharedPointer::create(); - return KAsync::start([timer, delay](KAsync::Future &future) { - timer->setSingleShot(true); - QObject::connect(timer.data(), &QTimer::timeout, [&future]() { - future.setFinished(); - }); - timer->start(delay); - }); -} - diff --git a/async/src/async.h b/async/src/async.h deleted file mode 100644 index 152f98e..0000000 --- a/async/src/async.h +++ /dev/null @@ -1,874 +0,0 @@ -/* - * Copyright 2014 - 2015 Daniel Vrátil - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library. If not, see . - */ - -#ifndef KASYNC_H -#define KASYNC_H - -#include "kasync_export.h" - -#include -#include -#include -#include -#include - -#include "future.h" -#include "debug.h" -#include "async_impl.h" - -#include -#include -#include - -#include - -#ifdef WITH_KJOB -#include -#endif - - -/* - * API to help write async code. - * - * This API is based around jobs that take lambdas to execute asynchronous tasks. Each async operation can take a continuation, - * that can then be used to execute further async operations. That way it is possible to build async chains of operations, - * that can be stored and executed later on. Jobs can be composed, similarly to functions. - * - * Relations between the components: - * * Job: API wrapper around Executors chain. Can be destroyed while still running, - * because the actual execution happens in the background - * * Executor: Describes task to execute. Executors form a linked list matching the - * order in which they will be executed. The Executor chain is destroyed when - * the parent Job is destroyed. However if the Job is still running it is - * guaranteed that the Executor chain will not be destroyed until the execution - * is finished. - * * Execution: The running execution of the task stored in Executor. Each call to Job::exec() - * instantiates new Execution chain, which makes it possible for the Job to be - * executed multiple times (even in parallel). - * * Future: Representation of the result that is being calculated - * - * - * TODO: Composed progress reporting - * TODO: Possibility to abort a job through future (perhaps optional?) - * TODO: Support for timeout, specified during exec call, after which the error handler gets called with a defined errorCode. - */ -namespace KAsync { - -template -class Executor; - -class JobBase; - -template -class Job; - -template -using ThenTask = typename detail::identity&)>>::type; -template -using SyncThenTask = typename detail::identity>::type; -template -using EachTask = typename detail::identity&)>>::type; -template -using SyncEachTask = typename detail::identity>::type; -template -using ReduceTask = typename detail::identity&)>>::type; -template -using SyncReduceTask = typename detail::identity>::type; - -using ErrorHandler = std::function; -using Condition = std::function; - -namespace Private -{ - -class ExecutorBase; -typedef QSharedPointer ExecutorBasePtr; - -struct KASYNC_EXPORT Execution { - Execution(const ExecutorBasePtr &executor); - ~Execution(); - void setFinished(); - - template - KAsync::Future* result() const - { - return static_cast*>(resultBase); - } - - void releaseFuture(); - bool errorWasHandled() const; - - ExecutorBasePtr executor; - FutureBase *resultBase; - bool isRunning; - bool isFinished; - - ExecutionPtr prevExecution; - -#ifndef QT_NO_DEBUG - Tracer *tracer; -#endif -}; - - -typedef QSharedPointer ExecutionPtr; - -class KASYNC_EXPORT ExecutorBase -{ - template - friend class Executor; - - template - friend class KAsync::Job; - - friend class Execution; - friend class KAsync::Tracer; - -public: - virtual ~ExecutorBase(); - virtual ExecutionPtr exec(const ExecutorBasePtr &self) = 0; - -protected: - ExecutorBase(const ExecutorBasePtr &parent); - - template - KAsync::Future* createFuture(const ExecutionPtr &execution) const; - - virtual bool hasErrorFunc() const = 0; - virtual bool handleError(const ExecutionPtr &execution) = 0; - - ExecutorBasePtr mPrev; - -#ifndef QT_NO_DEBUG - QString mExecutorName; -#endif -}; - -template -class Executor : public ExecutorBase -{ -protected: - Executor(ErrorHandler errorFunc, const Private::ExecutorBasePtr &parent) - : ExecutorBase(parent) - , mErrorFunc(errorFunc) - {} - - virtual ~Executor() {} - virtual void run(const ExecutionPtr &execution) = 0; - - ExecutionPtr exec(const ExecutorBasePtr &self); - bool hasErrorFunc() const { return (bool) mErrorFunc; } - bool handleError(const ExecutionPtr &execution); - - std::function mErrorFunc; -}; - -template -class ThenExecutor: public Executor::type, Out, In ...> -{ -public: - ThenExecutor(ThenTask then, ErrorHandler errorFunc, const ExecutorBasePtr &parent); - void run(const ExecutionPtr &execution); -private: - ThenTask mFunc; -}; - -template -class EachExecutor : public Executor -{ -public: - EachExecutor(EachTask each, ErrorHandler errorFunc, const ExecutorBasePtr &parent); - void run(const ExecutionPtr &execution); -private: - EachTask mFunc; - QVector*> mFutureWatchers; -}; - -template -class ReduceExecutor : public ThenExecutor -{ -public: - ReduceExecutor(ReduceTask reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent); -private: - ReduceTask mFunc; -}; - -template -class SyncThenExecutor : public Executor::type, Out, In ...> -{ -public: - SyncThenExecutor(SyncThenTask then, ErrorHandler errorFunc, const ExecutorBasePtr &parent); - void run(const ExecutionPtr &execution); - -private: - void run(const ExecutionPtr &execution, std::false_type); // !std::is_void - void run(const ExecutionPtr &execution, std::true_type); // std::is_void - SyncThenTask mFunc; -}; - -template -class SyncReduceExecutor : public SyncThenExecutor -{ -public: - SyncReduceExecutor(SyncReduceTask reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent); -private: - SyncReduceTask mFunc; -}; - -template -class SyncEachExecutor : public Executor -{ -public: - SyncEachExecutor(SyncEachTask each, ErrorHandler errorFunc, const ExecutorBasePtr &parent); - void run(const ExecutionPtr &execution); -private: - void run(KAsync::Future *future, const typename PrevOut::value_type &arg, std::false_type); // !std::is_void - void run(KAsync::Future *future, const typename PrevOut::value_type &arg, std::true_type); // std::is_void - SyncEachTask mFunc; -}; - -} // namespace Private - -/** - * Start an asynchronous job sequence. - * - * KAsync::start() is your starting point to build a chain of jobs to be executed - * asynchronously. - * - * @param func An asynchronous function to be executed. The function must have - * void return type, and accept exactly one argument of type @p KAsync::Future, - * where @p In is type of the result. - */ -template -Job start(ThenTask func, ErrorHandler errorFunc = ErrorHandler()); - -template -Job start(SyncThenTask func, ErrorHandler errorFunc = ErrorHandler()); - -#ifdef WITH_KJOB -template -Job start(); -#endif - -/** - * Async while loop. - * - * The loop continues while @param condition returns true. - */ -KASYNC_EXPORT Job dowhile(Condition condition, ThenTask func); - -/** - * Async while loop. - * - * Loop continues while body returns true. - */ -KASYNC_EXPORT Job dowhile(ThenTask body); - -/** - * Iterate over a container. - * - * Use in conjunction with .each - */ -template -Job iterate(const Out &container); - -/** - * Async delay. - */ -KASYNC_EXPORT Job wait(int delay); - -/** - * A null job. - * - * An async noop. - * - */ -template -Job null(); - -/** - * An error job. - * - * An async error. - * - */ -template -Job error(int errorCode = 1, const QString &errorMessage = QString()); - -class KASYNC_EXPORT JobBase -{ - template - friend class Job; - -public: - JobBase(const Private::ExecutorBasePtr &executor); - ~JobBase(); - -protected: - Private::ExecutorBasePtr mExecutor; -}; - -/** - * An Asynchronous job - * - * A single instance of Job represents a single method that will be executed - * asynchrously. The Job is started by @p Job::exec(), which returns @p KAsync::Future - * immediatelly. The Future will be set to finished state once the asynchronous - * task has finished. You can use @p KAsync::Future::waitForFinished() to wait for - * for the Future in blocking manner. - * - * It is possible to chain multiple Jobs one after another in different fashion - * (sequential, parallel, etc.). Calling Job::exec() will then return a pending - * @p KAsync::Future, and will execute the entire chain of jobs. - * - * @code - * auto job = Job::start>( - * [](KAsync::Future> &future) { - * MyREST::PendingUsers *pu = MyREST::requestListOfUsers(); - * QObject::connect(pu, &PendingOperation::finished, - * [&](PendingOperation *pu) { - * future->setValue(dynamic_cast(pu)->userIds()); - * future->setFinished(); - * }); - * }) - * .each, int>( - * [](const int &userId, KAsync::Future> &future) { - * MyREST::PendingUser *pu = MyREST::requestUserDetails(userId); - * QObject::connect(pu, &PendingOperation::finished, - * [&](PendingOperation *pu) { - * future->setValue(Qlist() << dynamic_cast(pu)->user()); - * future->setFinished(); - * }); - * }); - * - * KAsync::Future> usersFuture = job.exec(); - * usersFuture.waitForFinished(); - * QList users = usersFuture.value(); - * @endcode - * - * In the example above, calling @p job.exec() will first invoke the first job, - * which will retrieve a list of IDs, and then will invoke the second function - * for each single entry in the list returned by the first function. - */ -template -class Job : public JobBase -{ - template - friend class Job; - - template - friend Job start(KAsync::ThenTask func, ErrorHandler errorFunc); - - template - friend Job start(KAsync::SyncThenTask func, ErrorHandler errorFunc); - -#ifdef WITH_KJOB - template - friend Job start(); -#endif - -public: - template - Job then(ThenTask func, ErrorHandler errorFunc = ErrorHandler()) - { - return Job(Private::ExecutorBasePtr( - new Private::ThenExecutor(func, errorFunc, mExecutor))); - } - - template - Job then(SyncThenTask func, ErrorHandler errorFunc = ErrorHandler()) - { - return Job(Private::ExecutorBasePtr( - new Private::SyncThenExecutor(func, errorFunc, mExecutor))); - } - - template - Job then(Job otherJob, ErrorHandler errorFunc = ErrorHandler()) - { - return then(nestedJobWrapper(otherJob), errorFunc); - } - -#ifdef WITH_KJOB - template - Job then() - { - return start(); - } -#endif - - template - Job each(EachTask func, ErrorHandler errorFunc = ErrorHandler()) - { - eachInvariants(); - return Job(Private::ExecutorBasePtr( - new Private::EachExecutor(func, errorFunc, mExecutor))); - } - - template - Job each(SyncEachTask func, ErrorHandler errorFunc = ErrorHandler()) - { - eachInvariants(); - return Job(Private::ExecutorBasePtr( - new Private::SyncEachExecutor(func, errorFunc, mExecutor))); - } - - template - Job each(Job otherJob, ErrorHandler errorFunc = ErrorHandler()) - { - eachInvariants(); - return each(nestedJobWrapper(otherJob), errorFunc); - } - - template - Job reduce(ReduceTask func, ErrorHandler errorFunc = ErrorHandler()) - { - reduceInvariants(); - return Job(Private::ExecutorBasePtr( - new Private::ReduceExecutor(func, errorFunc, mExecutor))); - } - - template - Job reduce(SyncReduceTask func, ErrorHandler errorFunc = ErrorHandler()) - { - reduceInvariants(); - return Job(Private::ExecutorBasePtr( - new Private::SyncReduceExecutor(func, errorFunc, mExecutor))); - } - - template - Job reduce(Job otherJob, ErrorHandler errorFunc = ErrorHandler()) - { - return reduce(nestedJobWrapper(otherJob), errorFunc); - } - - template - KAsync::Future exec(FirstIn in) - { - // Inject a fake sync executor that will return the initial value - Private::ExecutorBasePtr first = mExecutor; - while (first->mPrev) { - first = first->mPrev; - } - auto init = new Private::SyncThenExecutor( - [in]() -> FirstIn { - return in; - }, - ErrorHandler(), Private::ExecutorBasePtr()); - first->mPrev = Private::ExecutorBasePtr(init); - - auto result = exec(); - // Remove the injected executor - first->mPrev.reset(); - return result; - } - - KAsync::Future exec() - { - Private::ExecutionPtr execution = mExecutor->exec(mExecutor); - KAsync::Future result = *execution->result(); - - return result; - } - -private: - Job(Private::ExecutorBasePtr executor) - : JobBase(executor) - {} - - template - void eachInvariants() - { - static_assert(detail::isIterable::value, - "The 'Each' task can only be connected to a job that returns a list or an array."); - static_assert(std::is_void::value || detail::isIterable::value, - "The result type of 'Each' task must be void, a list or an array."); - } - - template - void reduceInvariants() - { - static_assert(KAsync::detail::isIterable::value, - "The 'Result' task can only be connected to a job that returns a list or an array"); - static_assert(std::is_same::value, - "The return type of previous task must be compatible with input type of this task"); - } - - template - inline std::function&)> nestedJobWrapper(Job otherJob) { - return [otherJob](InOther ... in, KAsync::Future &future) { - // copy by value is const - auto job = otherJob; - FutureWatcher *watcher = new FutureWatcher(); - QObject::connect(watcher, &FutureWatcherBase::futureReady, - [watcher, future]() { - // FIXME: We pass future by value, because using reference causes the - // future to get deleted before this lambda is invoked, leading to crash - // in copyFutureValue() - // copy by value is const - auto outFuture = future; - KAsync::detail::copyFutureValue(watcher->future(), outFuture); - if (watcher->future().errorCode()) { - outFuture.setError(watcher->future().errorCode(), watcher->future().errorMessage()); - } else { - outFuture.setFinished(); - } - delete watcher; - }); - watcher->setFuture(job.exec(in ...)); - }; - } -}; - -} // namespace KAsync - - -// ********** Out of line definitions **************** - -namespace KAsync { - -template -Job start(ThenTask func, ErrorHandler error) -{ - return Job(Private::ExecutorBasePtr( - new Private::ThenExecutor(func, error, Private::ExecutorBasePtr()))); -} - -template -Job start(SyncThenTask func, ErrorHandler error) -{ - return Job(Private::ExecutorBasePtr( - new Private::SyncThenExecutor(func, error, Private::ExecutorBasePtr()))); -} - -#ifdef WITH_KJOB -template -Job start() -{ - return Job(Private::ExecutorBasePtr( - new Private::ThenExecutor([](const Args & ... args, KAsync::Future &future) - { - KJobType *job = new KJobType(args ...); - job->connect(job, &KJob::finished, - [&future](KJob *job) { - if (job->error()) { - future.setError(job->error(), job->errorString()); - } else { - future.setValue((static_cast(job)->*KJobResultMethod)()); - future.setFinished(); - } - }); - job->start(); - }, ErrorHandler(), Private::ExecutorBasePtr()))); -} -#endif - - -template -Job null() -{ - return KAsync::start( - [](KAsync::Future &future) { - future.setFinished(); - }); -} - -template -Job error(int errorCode, const QString &errorMessage) -{ - return KAsync::start( - [errorCode, errorMessage](KAsync::Future &future) { - future.setError(errorCode, errorMessage); - }); -} - -template -Job iterate(const Out &container) -{ - return KAsync::start( - [container]() { - return container; - }); -} - - -namespace Private { - -template -KAsync::Future* ExecutorBase::createFuture(const ExecutionPtr &execution) const -{ - return new KAsync::Future(execution); -} - -template -ExecutionPtr Executor::exec(const ExecutorBasePtr &self) -{ - // Passing 'self' to execution ensures that the Executor chain remains - // valid until the entire execution is finished - ExecutionPtr execution = ExecutionPtr::create(self); -#ifndef QT_NO_DEBUG - execution->tracer = new Tracer(execution.data()); // owned by execution -#endif - - // chainup - execution->prevExecution = mPrev ? mPrev->exec(mPrev) : ExecutionPtr(); - - execution->resultBase = ExecutorBase::createFuture(execution); - auto fw = new KAsync::FutureWatcher(); - QObject::connect(fw, &KAsync::FutureWatcher::futureReady, - [fw, execution, this]() { - handleError(execution); - execution->setFinished(); - delete fw; - }); - fw->setFuture(*execution->result()); - - KAsync::Future *prevFuture = execution->prevExecution ? execution->prevExecution->result() : nullptr; - if (!prevFuture || prevFuture->isFinished()) { - if (prevFuture) { // prevFuture implies execution->prevExecution - if (prevFuture->errorCode()) { - // Propagate the errorCode and message to the outer Future - execution->resultBase->setError(prevFuture->errorCode(), prevFuture->errorMessage()); - if (!execution->errorWasHandled()) { - if (handleError(execution)) { - return execution; - } - } else { - return execution; - } - } else { - // Propagate error (if any) - } - } - - execution->isRunning = true; - run(execution); - } else { - auto prevFutureWatcher = new KAsync::FutureWatcher(); - QObject::connect(prevFutureWatcher, &KAsync::FutureWatcher::futureReady, - [prevFutureWatcher, execution, this]() { - auto prevFuture = prevFutureWatcher->future(); - assert(prevFuture.isFinished()); - delete prevFutureWatcher; - auto prevExecutor = execution->executor->mPrev; - if (prevFuture.errorCode()) { - execution->resultBase->setError(prevFuture.errorCode(), prevFuture.errorMessage()); - if (!execution->errorWasHandled()) { - if (handleError(execution)) { - return; - } - } else { - return; - } - } - - - // propagate error (if any) - execution->isRunning = true; - run(execution); - }); - - prevFutureWatcher->setFuture(*static_cast*>(prevFuture)); - } - - return execution; -} - -template -bool Executor::handleError(const ExecutionPtr &execution) -{ - assert(execution->resultBase->isFinished()); - if (execution->resultBase->errorCode()) { - if (mErrorFunc) { - mErrorFunc(execution->resultBase->errorCode(), - execution->resultBase->errorMessage()); - return true; - } - } - - return false; -} - - -template -ThenExecutor::ThenExecutor(ThenTask then, ErrorHandler error, const ExecutorBasePtr &parent) - : Executor::type, Out, In ...>(error, parent) - , mFunc(then) -{ - STORE_EXECUTOR_NAME("ThenExecutor", Out, In ...); -} - -template -void ThenExecutor::run(const ExecutionPtr &execution) -{ - KAsync::Future::type> *prevFuture = nullptr; - if (execution->prevExecution) { - prevFuture = execution->prevExecution->result::type>(); - assert(prevFuture->isFinished()); - } - - ThenExecutor::mFunc(prevFuture ? prevFuture->value() : In() ..., *execution->result()); -} - -template -EachExecutor::EachExecutor(EachTask each, ErrorHandler error, const ExecutorBasePtr &parent) - : Executor(error, parent) - , mFunc(each) -{ - STORE_EXECUTOR_NAME("EachExecutor", PrevOut, Out, In); -} - -template -void EachExecutor::run(const ExecutionPtr &execution) -{ - assert(execution->prevExecution); - auto prevFuture = execution->prevExecution->result(); - assert(prevFuture->isFinished()); - - auto out = execution->result(); - if (prevFuture->value().isEmpty()) { - out->setFinished(); - return; - } - - for (auto arg : prevFuture->value()) { - //We have to manually manage the lifetime of these temporary futures - KAsync::Future *future = new KAsync::Future(); - EachExecutor::mFunc(arg, *future); - auto fw = new KAsync::FutureWatcher(); - mFutureWatchers.append(fw); - QObject::connect(fw, &KAsync::FutureWatcher::futureReady, - [out, fw, this, future]() { - assert(fw->future().isFinished()); - const int index = mFutureWatchers.indexOf(fw); - assert(index > -1); - mFutureWatchers.removeAt(index); - KAsync::detail::aggregateFutureValue(fw->future(), *out); - if (mFutureWatchers.isEmpty()) { - out->setFinished(); - } - delete fw; - delete future; - }); - fw->setFuture(*future); - } -} - -template -ReduceExecutor::ReduceExecutor(ReduceTask reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent) - : ThenExecutor(reduce, errorFunc, parent) -{ - STORE_EXECUTOR_NAME("ReduceExecutor", Out, In); -} - -template -SyncThenExecutor::SyncThenExecutor(SyncThenTask then, ErrorHandler errorFunc, const ExecutorBasePtr &parent) - : Executor::type, Out, In ...>(errorFunc, parent) - , mFunc(then) -{ - STORE_EXECUTOR_NAME("SyncThenExecutor", Out, In ...); -} - -template -void SyncThenExecutor::run(const ExecutionPtr &execution) -{ - if (execution->prevExecution) { - assert(execution->prevExecution->resultBase->isFinished()); - } - - run(execution, std::is_void()); - execution->resultBase->setFinished(); -} - -template -void SyncThenExecutor::run(const ExecutionPtr &execution, std::false_type) -{ - KAsync::Future::type> *prevFuture = - execution->prevExecution - ? execution->prevExecution->result::type>() - : nullptr; - (void) prevFuture; // silence 'set but not used' warning - KAsync::Future *future = execution->result(); - future->setValue(SyncThenExecutor::mFunc(prevFuture ? prevFuture->value() : In() ...)); -} - -template -void SyncThenExecutor::run(const ExecutionPtr &execution, std::true_type) -{ - KAsync::Future::type> *prevFuture = - execution->prevExecution - ? execution->prevExecution->result::type>() - : nullptr; - (void) prevFuture; // silence 'set but not used' warning - SyncThenExecutor::mFunc(prevFuture ? prevFuture->value() : In() ...); -} - -template -SyncEachExecutor::SyncEachExecutor(SyncEachTask each, ErrorHandler errorFunc, const ExecutorBasePtr &parent) - : Executor(errorFunc, parent) - , mFunc(each) -{ - STORE_EXECUTOR_NAME("SyncEachExecutor", PrevOut, Out, In); -} - -template -void SyncEachExecutor::run(const ExecutionPtr &execution) -{ - assert(execution->prevExecution); - auto *prevFuture = execution->prevExecution->result(); - assert(prevFuture->isFinished()); - - auto out = execution->result(); - if (prevFuture->value().isEmpty()) { - out->setFinished(); - return; - } - - for (auto arg : prevFuture->value()) { - run(out, arg, std::is_void()); - } - out->setFinished(); -} - -template -void SyncEachExecutor::run(KAsync::Future *out, const typename PrevOut::value_type &arg, std::false_type) -{ - out->setValue(out->value() + SyncEachExecutor::mFunc(arg)); -} - -template -void SyncEachExecutor::run(KAsync::Future * /* unused */, const typename PrevOut::value_type &arg, std::true_type) -{ - SyncEachExecutor::mFunc(arg); -} - -template -SyncReduceExecutor::SyncReduceExecutor(SyncReduceTask reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent) - : SyncThenExecutor(reduce, errorFunc, parent) -{ - STORE_EXECUTOR_NAME("SyncReduceExecutor", Out, In); -} - - -} // namespace Private - -} // namespace KAsync - - - -#endif // KASYNC_H - - diff --git a/async/src/async_impl.h b/async/src/async_impl.h deleted file mode 100644 index 5b4e393..0000000 --- a/async/src/async_impl.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2014 - 2015 Daniel Vrátil - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library. If not, see . - */ - -#ifndef KASYNC_IMPL_H -#define KASYNC_IMPL_H - -#include "async.h" -#include - -namespace KAsync { - -namespace detail { - -template -struct identity -{ - typedef T type; -}; - -template -struct isIterable { - enum { value = 0 }; -}; - -template -struct isIterable::type> { - enum { value = 1 }; -}; - -template -struct prevOut { - using type = typename std::tuple_element<0, std::tuple>::type; -}; - -template -inline typename std::enable_if::value, void>::type -copyFutureValue(const KAsync::Future &in, KAsync::Future &out) -{ - out.setValue(in.value()); -} - -template -inline typename std::enable_if::value, void>::type -copyFutureValue(const KAsync::Future &in, KAsync::Future &out) -{ - // noop -} - -template -inline typename std::enable_if::value, void>::type -aggregateFutureValue(const KAsync::Future &in, KAsync::Future &out) -{ - out.setValue(out.value() + in.value()); -} - -template -inline typename std::enable_if::value, void>::type -aggregateFutureValue(const KAsync::Future &in, KAsync::Future &out) -{ - // noop -} - -} // namespace Detail - -} // namespace KAsync - -#endif // KASYNC_IMPL_H diff --git a/async/src/debug.cpp b/async/src/debug.cpp deleted file mode 100644 index 64a3a3b..0000000 --- a/async/src/debug.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2015 Daniel Vrátil - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library. If not, see . - */ - -#include "debug.h" -#include "async.h" - -#include - -#ifdef __GNUG__ -#include -#include -#endif - -namespace KAsync -{ - -Q_LOGGING_CATEGORY(Debug, "org.kde.async", QtWarningMsg); -Q_LOGGING_CATEGORY(Trace, "org.kde.async.trace", QtWarningMsg); - -QString demangleName(const char *name) -{ -#ifdef __GNUG__ - int status = 1; // uses -3 to 0 error codes - std::unique_ptr demangled(abi::__cxa_demangle(name, 0, 0, &status), std::free); - if (status == 0) { - return QString::fromLatin1(demangled.get()); - } -#endif - return QString::fromLatin1(name); -} - -} - -using namespace KAsync; - -int Tracer::lastId = 0; - -Tracer::Tracer(Private::Execution *execution) - : mId(lastId++) - , mExecution(execution) -{ - msg(KAsync::Tracer::Start); -} - -Tracer::~Tracer() -{ - msg(KAsync::Tracer::End); - // FIXME: Does this work on parallel executions? - --lastId; - --mId; -} - -void Tracer::msg(Tracer::MsgType msgType) -{ -#ifndef QT_NO_DEBUG - qCDebug(Trace).nospace() << (QString().fill(QLatin1Char(' '), mId * 2) % - (msgType == KAsync::Tracer::Start ? QStringLiteral(" START ") : QStringLiteral(" END ")) % - QString::number(mId) % QStringLiteral(" ") % - mExecution->executor->mExecutorName); -#endif -} diff --git a/async/src/debug.h b/async/src/debug.h deleted file mode 100644 index b2b2ff7..0000000 --- a/async/src/debug.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2015 Daniel Vrátil - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library. If not, see . - */ - -#ifndef KASYNC_DEBUG_H -#define KASYNC_DEBUG_H - -#include "kasync_export.h" - -#include -#include - -#ifndef QT_NO_DEBUG -#include -#endif - -namespace KAsync -{ - -Q_DECLARE_LOGGING_CATEGORY(Debug) -Q_DECLARE_LOGGING_CATEGORY(Trace) - -KASYNC_EXPORT QString demangleName(const char *name); - -namespace Private -{ -class Execution; -} - -class KASYNC_EXPORT Tracer -{ -public: - Tracer(Private::Execution *execution); - ~Tracer(); - -private: - enum MsgType { - Start, - End - }; - void msg(MsgType); - - int mId; - Private::Execution *mExecution; - - static int lastId; -}; - -} - -#ifndef QT_NO_DEBUG - template - QString storeExecutorNameExpanded() { - return KAsync::demangleName(typeid(T).name()); - } - - template - typename std::enable_if::type - storeExecutorNameExpanded() { - return storeExecutorNameExpanded() % QStringLiteral(", ") % storeExecutorNameExpanded(); - } - - #define STORE_EXECUTOR_NAME(name, ...) \ - ExecutorBase::mExecutorName = QStringLiteral(name) % QStringLiteral("<") % storeExecutorNameExpanded<__VA_ARGS__>() % QStringLiteral(">") -#else - #define STORE_EXECUTOR_NAME(...) -#endif - -#endif // KASYNC_DEBUG_H \ No newline at end of file diff --git a/async/src/future.cpp b/async/src/future.cpp deleted file mode 100644 index 9281cc8..0000000 --- a/async/src/future.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright 2014 Daniel Vrátil - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library. If not, see . - */ - -#include "future.h" -#include "async.h" - -using namespace KAsync; - -FutureBase::PrivateBase::PrivateBase(const Private::ExecutionPtr &execution) - : finished(false) - , errorCode(0) - , mExecution(execution) -{ -} - -FutureBase::PrivateBase::~PrivateBase() -{ - Private::ExecutionPtr executionPtr = mExecution.toStrongRef(); - if (executionPtr) { - executionPtr->releaseFuture(); - releaseExecution(); - } -} - -void FutureBase::PrivateBase::releaseExecution() -{ - mExecution.clear(); -} - - - -FutureBase::FutureBase() - : d(nullptr) -{ -} - -FutureBase::FutureBase(FutureBase::PrivateBase *dd) - : d(dd) -{ -} - -FutureBase::FutureBase(const KAsync::FutureBase &other) - : d(other.d) -{ -} - -FutureBase::~FutureBase() -{ -} - -void FutureBase::releaseExecution() -{ - d->releaseExecution(); -} - -void FutureBase::setFinished() -{ - if (isFinished()) { - return; - } - d->finished = true; - for (auto watcher : d->watchers) { - if (watcher) { - watcher->futureReadyCallback(); - } - } -} - -bool FutureBase::isFinished() const -{ - return d->finished; -} - -void FutureBase::setError(int code, const QString &message) -{ - d->errorCode = code; - d->errorMessage = message; - setFinished(); -} - -int FutureBase::errorCode() const -{ - return d->errorCode; -} - -QString FutureBase::errorMessage() const -{ - return d->errorMessage; -} - -void FutureBase::setProgress(int processed, int total) -{ - setProgress((qreal) processed / total); -} - -void FutureBase::setProgress(qreal progress) -{ - for (auto watcher : d->watchers) { - if (watcher) { - watcher->futureProgressCallback(progress); - } - } -} - - - -void FutureBase::addWatcher(FutureWatcherBase* watcher) -{ - d->watchers.append(QPointer(watcher)); -} - - - - - -FutureWatcherBase::FutureWatcherBase(QObject *parent) - : QObject(parent) - , d(new FutureWatcherBase::Private) -{ -} - -FutureWatcherBase::~FutureWatcherBase() -{ - delete d; -} - -void FutureWatcherBase::futureReadyCallback() -{ - Q_EMIT futureReady(); -} - -void FutureWatcherBase::futureProgressCallback(qreal progress) -{ - Q_EMIT futureProgress(progress); -} - -void FutureWatcherBase::setFutureImpl(const FutureBase &future) -{ - d->future = future; - d->future.addWatcher(this); - if (future.isFinished()) { - futureReadyCallback(); - } -} diff --git a/async/src/future.h b/async/src/future.h deleted file mode 100644 index b2b723e..0000000 --- a/async/src/future.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright 2014 Daniel Vrátil - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library. If not, see . - */ - -#ifndef FUTURE_H -#define FUTURE_H - -#include "kasync_export.h" - -class QEventLoop; - -#include - -#include -#include -#include -#include - -namespace KAsync { - -class FutureWatcherBase; -template -class FutureWatcher; - -namespace Private { -class Execution; -class ExecutorBase; - -typedef QSharedPointer ExecutionPtr; -} // namespace Private - -class KASYNC_EXPORT FutureBase -{ - friend class KAsync::Private::Execution; - friend class FutureWatcherBase; - -public: - virtual ~FutureBase(); - - void setFinished(); - bool isFinished() const; - void setError(int code = 1, const QString &message = QString()); - int errorCode() const; - QString errorMessage() const; - - void setProgress(qreal progress); - void setProgress(int processed, int total); - -protected: - class PrivateBase : public QSharedData - { - public: - PrivateBase(const KAsync::Private::ExecutionPtr &execution); - virtual ~PrivateBase(); - - void releaseExecution(); - - bool finished; - int errorCode; - QString errorMessage; - - QVector> watchers; - private: - QWeakPointer mExecution; - }; - - FutureBase(); - FutureBase(FutureBase::PrivateBase *dd); - FutureBase(const FutureBase &other); - - void addWatcher(KAsync::FutureWatcherBase *watcher); - void releaseExecution(); - -protected: - QExplicitlySharedDataPointer d; -}; - -template -class FutureWatcher; - -template -class Future; - -template -class FutureGeneric : public FutureBase -{ - friend class FutureWatcher; - -public: - void waitForFinished() const - { - if (isFinished()) { - return; - } - FutureWatcher watcher; - QEventLoop eventLoop; - QObject::connect(&watcher, &KAsync::FutureWatcher::futureReady, - &eventLoop, &QEventLoop::quit); - watcher.setFuture(*static_cast*>(this)); - eventLoop.exec(); - } - -protected: - FutureGeneric(const KAsync::Private::ExecutionPtr &execution) - : FutureBase(new Private(execution)) - {} - - FutureGeneric(const FutureGeneric &other) - : FutureBase(other) - {} - -protected: - class Private : public FutureBase::PrivateBase - { - public: - Private(const KAsync::Private::ExecutionPtr &execution) - : FutureBase::PrivateBase(execution) - {} - - typename std::conditional::value, int /* dummy */, T>::type - value; - }; -}; - - -template -class Future : public FutureGeneric -{ - friend class KAsync::Private::ExecutorBase; - - template - friend class KAsync::FutureWatcher; - -public: - Future() - : FutureGeneric(KAsync::Private::ExecutionPtr()) - {} - - Future(const Future &other) - : FutureGeneric(other) - {} - - void setValue(const T &value) - { - static_cast::Private*>(this->d.data())->value = value; - } - - T value() const - { - return static_cast::Private*>(this->d.data())->value; - } - -protected: - Future(const KAsync::Private::ExecutionPtr &execution) - : FutureGeneric(execution) - {} - -}; - -template<> -class Future : public FutureGeneric -{ - friend class KAsync::Private::ExecutorBase; - -public: - Future() - : FutureGeneric(KAsync::Private::ExecutionPtr()) - {} - - Future(const Future &other) - : FutureGeneric(other) - {} - -protected: - Future(const KAsync::Private::ExecutionPtr &execution) - : FutureGeneric(execution) - {} -}; - - - - - -class KASYNC_EXPORT FutureWatcherBase : public QObject -{ - Q_OBJECT - - friend class FutureBase; - -Q_SIGNALS: - void futureReady(); - void futureProgress(qreal progress); - -protected: - FutureWatcherBase(QObject *parent = nullptr); - virtual ~FutureWatcherBase(); - - void futureReadyCallback(); - void futureProgressCallback(qreal progress); - - void setFutureImpl(const KAsync::FutureBase &future); - -protected: - class Private { - public: - KAsync::FutureBase future; - }; - - Private * const d; - -private: - Q_DISABLE_COPY(FutureWatcherBase); -}; - -template -class FutureWatcher : public FutureWatcherBase -{ - friend class KAsync::FutureGeneric; - -public: - FutureWatcher(QObject *parent = nullptr) - : FutureWatcherBase(parent) - {} - - ~FutureWatcher() - {} - - void setFuture(const KAsync::Future &future) - { - setFutureImpl(*static_cast(&future)); - } - - KAsync::Future future() const - { - return *static_cast*>(&d->future); - } - -private: - Q_DISABLE_COPY(FutureWatcher); -}; - -} // namespace Async - -#endif // FUTURE_H -- cgit v1.2.3