From 67d47d893bc582fbd06da8bd93a1c416fa314ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Thu, 11 Dec 2014 11:07:04 +0100 Subject: Prototype of Async library --- async/src/CMakeLists.txt | 6 ++ async/src/async.cpp | 67 ++++++++++++++++++++ async/src/async.h | 158 +++++++++++++++++++++++++++++++++++++++++++++++ async/src/async_impl.h | 32 ++++++++++ async/src/future.h | 90 +++++++++++++++++++++++++++ 5 files changed, 353 insertions(+) create mode 100644 async/src/CMakeLists.txt create mode 100644 async/src/async.cpp create mode 100644 async/src/async.h create mode 100644 async/src/async_impl.h create mode 100644 async/src/future.h (limited to 'async/src') diff --git a/async/src/CMakeLists.txt b/async/src/CMakeLists.txt new file mode 100644 index 0000000..a98d8ce --- /dev/null +++ b/async/src/CMakeLists.txt @@ -0,0 +1,6 @@ +set(async_SRCS + async.cpp +) + +add_library(akonadi2async SHARED ${async_SRCS}) +target_link_libraries(akonadi2async Qt5::Core) diff --git a/async/src/async.cpp b/async/src/async.cpp new file mode 100644 index 0000000..5c89e53 --- /dev/null +++ b/async/src/async.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2014 Daniel Vrátil + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "async.h" + +#include +#include +#include + + +using namespace Async; + +FutureBase::FutureBase() + : mFinished(false) + , mWaitLoop(nullptr) +{ + +} + +FutureBase::FutureBase(const Async::FutureBase &other) + : mFinished(other.mFinished) + , mWaitLoop(other.mWaitLoop) +{ +} + +void FutureBase::setFinished() +{ + mFinished = true; + if (mWaitLoop && mWaitLoop->isRunning()) { + mWaitLoop->quit(); + } +} + +bool FutureBase::isFinished() const +{ + return mFinished; +} + +void FutureBase::waitForFinished() +{ + if (mFinished) { + return; + } + + mWaitLoop = new QEventLoop; + mWaitLoop->exec(QEventLoop::ExcludeUserInputEvents); + delete mWaitLoop; + mWaitLoop = 0; +} diff --git a/async/src/async.h b/async/src/async.h new file mode 100644 index 0000000..790dfe9 --- /dev/null +++ b/async/src/async.h @@ -0,0 +1,158 @@ +/* + * Copyright 2014 Daniel Vrátil + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef ASYNC_H +#define ASYNC_H + +#include +#include +#include +#include +#include + +#include "future.h" +#include "async_impl.h" + + +namespace Async { + +template +class Job; + +template +Job start(const std::function(In ...)> &func); + + +class JobBase +{ +public: + JobBase(JobBase *prev = nullptr) + : mPrev(prev) + , mResult(0) + {} + + virtual void exec() = 0; + +public: + JobBase *mPrev; + void *mResult; +}; + +namespace Private { + + template + typename std::enable_if::value, void>::type + doExec(JobBase *prev, JobBase *jobBase); + + template + typename std::enable_if::type + doExec(JobBase *prev, JobBase *jobBase, int * /* disambiguate */ = 0); +} + +template +class Job : public JobBase +{ + template + friend class Job; + + template + friend Job start(F_ func); + +public: + ~Job() + { + // Can't delete in JobBase, since we don't know the type + // and deleting void* is undefined + delete reinterpret_cast*>(mResult); + } + + template + Job then(F func) + { + Job job(this); + job.mFunc = func; + return job; + } + + Async::Future result() const + { + return *reinterpret_cast*>(mResult); + } + + + void exec() + { + Async::Private::doExec(mPrev, this); + } + +private: + Job(JobBase *parent = nullptr) + : JobBase(parent) + {} + +public: + std::function(In ...)> mFunc; +}; + +template +Job start(F func) +{ + Job job; + job.mFunc = std::function(In ...)>(func); + return job; +} + +} // namespace Async + +template +typename std::enable_if::value, void>::type +Async::Private::doExec(JobBase *prev, JobBase *jobBase) +{ + prev->exec(); + Async::Future *in = reinterpret_cast*>(prev->mResult); + assert(in->isFinished()); + + Job *job = dynamic_cast*>(jobBase); + Async::Future *out = new Async::Future(job->mFunc(in->value())); + out->waitForFinished(); + job->mResult = reinterpret_cast(out); +}; + +template +typename std::enable_if::type +Async::Private::doExec(JobBase *prev, JobBase *jobBase, int * /* disambiguation */ = 0) +{ + if (prev) { + prev->exec(); + Async::Future *in = reinterpret_cast*>(prev->mResult); + assert(in->isFinished()); + } + + Job *job = dynamic_cast*>(jobBase); + Async::Future *out = new Async::Future(job->mFunc()); + out->waitForFinished(); + job->mResult = reinterpret_cast(out); +}; + + +#endif // ASYNC_H + + diff --git a/async/src/async_impl.h b/async/src/async_impl.h new file mode 100644 index 0000000..46bc25d --- /dev/null +++ b/async/src/async_impl.h @@ -0,0 +1,32 @@ +/* + * Copyright 2014 Daniel Vrátil + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef ASYNC_IMPL_H +#define ASYNC_IMPL_H + +#include "async.h" + +namespace Async { + + +} // namespace Async + +#endif // ASYNC_IMPL_H \ No newline at end of file diff --git a/async/src/future.h b/async/src/future.h new file mode 100644 index 0000000..c53ef56 --- /dev/null +++ b/async/src/future.h @@ -0,0 +1,90 @@ +/* + * Copyright 2014 Daniel Vrátil + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License or (at your option) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef FUTURE_H +#define FUTURE_H + +class QEventLoop; + +namespace Async { + +class FutureBase +{ +public: + FutureBase(); + FutureBase(const FutureBase &other); + void setFinished(); + bool isFinished() const; + void waitForFinished(); + +protected: + bool mFinished; + QEventLoop *mWaitLoop; +}; + +template +class Future : public FutureBase +{ +public: + Future() + : FutureBase() + {} + + Future(const Future &other) + : FutureBase(other) + , mValue(other.mValue) + {} + + Future(const T &val) + : FutureBase() + , mValue(val) + {} + + void setValue(const T &val) + { + mValue = val; + } + + T value() const + { + return mValue; + } + +private: + T mValue; +}; + +template<> +class Future : public FutureBase +{ +public: + Future() + : FutureBase() + {} + + Future(const Future &other) + : FutureBase(other) + {} +}; + +} // namespace Async + +#endif // FUTURE_H -- cgit v1.2.3