summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rw-r--r--async/CMakeLists.txt2
-rw-r--r--async/autotests/CMakeLists.txt5
-rw-r--r--async/autotests/asynctest.cpp98
-rw-r--r--async/src/CMakeLists.txt6
-rw-r--r--async/src/async.cpp67
-rw-r--r--async/src/async.h158
-rw-r--r--async/src/async_impl.h32
-rw-r--r--async/src/future.h90
9 files changed, 461 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 514895f..3f86163 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -55,4 +55,7 @@ add_subdirectory(dummyresource)
55# some tests 55# some tests
56add_subdirectory(tests) 56add_subdirectory(tests)
57 57
58# async library prototype
59add_subdirectory(async)
60
58feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) 61feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/async/CMakeLists.txt b/async/CMakeLists.txt
new file mode 100644
index 0000000..19ac407
--- /dev/null
+++ b/async/CMakeLists.txt
@@ -0,0 +1,2 @@
1add_subdirectory(src)
2add_subdirectory(autotests) \ No newline at end of file
diff --git a/async/autotests/CMakeLists.txt b/async/autotests/CMakeLists.txt
new file mode 100644
index 0000000..a2bedc8
--- /dev/null
+++ b/async/autotests/CMakeLists.txt
@@ -0,0 +1,5 @@
1include_directories(../src ${CMAKE_CURRENT_BINARY_DIR})
2
3add_executable(asynctest asynctest.cpp)
4qt5_use_modules(asynctest Test)
5target_link_libraries(asynctest akonadi2async Qt5::Core Qt5::Test) \ No newline at end of file
diff --git a/async/autotests/asynctest.cpp b/async/autotests/asynctest.cpp
new file mode 100644
index 0000000..f2a70a4
--- /dev/null
+++ b/async/autotests/asynctest.cpp
@@ -0,0 +1,98 @@
1/*
2 * Copyright 2014 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License or (at your option) version 3 or any later version
8 * accepted by the membership of KDE e.V. (or its successor approved
9 * by the membership of KDE e.V.), which shall act as a proxy
10 * defined in Section 14 of version 3 of the license.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "../src/async.h"
23
24#include <QObject>
25#include <QString>
26#include <QTimer>
27#include <QtTest/QTest>
28
29class AsyncTest : public QObject
30{
31 Q_OBJECT
32
33public:
34 AsyncTest()
35 {}
36
37 ~AsyncTest()
38 {}
39
40private Q_SLOTS:
41 void testSyncPromises();
42 void testAsyncPromises();
43};
44
45void AsyncTest::testSyncPromises()
46{
47 auto baseJob = Async::start<int>(
48 []() -> Async::Future<int> {
49 auto f = Async::Future<int>(42);
50 f.setFinished();
51 return f;
52 })
53 .then<QString, int>(
54 [](int v) -> Async::Future<QString> {
55 auto f = Async::Future<QString>("Result is " + QString::number(v));
56 f.setFinished();
57 return f;
58 });
59
60 auto job = baseJob.then<QString, QString>(
61 [](const QString &v) -> Async::Future<QString> {
62 auto f = Async::Future<QString>(v.toUpper());
63 f.setFinished();
64 return f;
65 });
66
67 job.exec();
68 Async::Future<QString> future = job.result();
69
70 QCOMPARE(future.value(), QString::fromLatin1("RESULT IS 42"));
71}
72
73void AsyncTest::testAsyncPromises()
74{
75 auto job = Async::start<int>(
76 []() -> Async::Future<int> {
77 Async::Future<int> future(-1);
78 QTimer *timer = new QTimer();
79 QObject::connect(timer, &QTimer::timeout,
80 [&]() {
81 future.setValue(42);
82 future.setFinished();
83 timer->deleteLater();
84 });
85 timer->setSingleShot(true);
86 timer->start(200);
87 return future;
88 });
89
90 job.exec();
91 Async::Future<int> future = job.result();
92 QCOMPARE(future.value(), 42);
93}
94
95
96QTEST_MAIN(AsyncTest);
97
98#include "asynctest.moc"
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 @@
1set(async_SRCS
2 async.cpp
3)
4
5add_library(akonadi2async SHARED ${async_SRCS})
6target_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 @@
1/*
2 * Copyright 2014 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License or (at your option) version 3 or any later version
8 * accepted by the membership of KDE e.V. (or its successor approved
9 * by the membership of KDE e.V.), which shall act as a proxy
10 * defined in Section 14 of version 3 of the license.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "async.h"
23
24#include <QCoreApplication>
25#include <QDebug>
26#include <QEventLoop>
27
28
29using namespace Async;
30
31FutureBase::FutureBase()
32 : mFinished(false)
33 , mWaitLoop(nullptr)
34{
35
36}
37
38FutureBase::FutureBase(const Async::FutureBase &other)
39 : mFinished(other.mFinished)
40 , mWaitLoop(other.mWaitLoop)
41{
42}
43
44void FutureBase::setFinished()
45{
46 mFinished = true;
47 if (mWaitLoop && mWaitLoop->isRunning()) {
48 mWaitLoop->quit();
49 }
50}
51
52bool FutureBase::isFinished() const
53{
54 return mFinished;
55}
56
57void FutureBase::waitForFinished()
58{
59 if (mFinished) {
60 return;
61 }
62
63 mWaitLoop = new QEventLoop;
64 mWaitLoop->exec(QEventLoop::ExcludeUserInputEvents);
65 delete mWaitLoop;
66 mWaitLoop = 0;
67}
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 @@
1/*
2 * Copyright 2014 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License or (at your option) version 3 or any later version
8 * accepted by the membership of KDE e.V. (or its successor approved
9 * by the membership of KDE e.V.), which shall act as a proxy
10 * defined in Section 14 of version 3 of the license.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef ASYNC_H
23#define ASYNC_H
24
25#include <functional>
26#include <list>
27#include <type_traits>
28#include <iostream>
29#include <cassert>
30
31#include "future.h"
32#include "async_impl.h"
33
34
35namespace Async {
36
37template<typename Out, typename ... In>
38class Job;
39
40template<typename Out, typename ... In>
41Job<Out, In ...> start(const std::function<Async::Future<Out>(In ...)> &func);
42
43
44class JobBase
45{
46public:
47 JobBase(JobBase *prev = nullptr)
48 : mPrev(prev)
49 , mResult(0)
50 {}
51
52 virtual void exec() = 0;
53
54public:
55 JobBase *mPrev;
56 void *mResult;
57};
58
59namespace Private {
60
61 template<typename Out, typename In>
62 typename std::enable_if<!std::is_void<In>::value, void>::type
63 doExec(JobBase *prev, JobBase *jobBase);
64
65 template<typename Out, typename ... In>
66 typename std::enable_if<sizeof...(In) == 0, void>::type
67 doExec(JobBase *prev, JobBase *jobBase, int * /* disambiguate */ = 0);
68}
69
70template<typename Out, typename ... In>
71class Job : public JobBase
72{
73 template<typename Out_, typename ... In_>
74 friend class Job;
75
76 template<typename Out_, typename ... In_, typename F_>
77 friend Job<Out_, In_ ...> start(F_ func);
78
79public:
80 ~Job()
81 {
82 // Can't delete in JobBase, since we don't know the type
83 // and deleting void* is undefined
84 delete reinterpret_cast<Async::Future<Out>*>(mResult);
85 }
86
87 template<typename Out_, typename ... In_, typename F>
88 Job<Out_, In_ ...> then(F func)
89 {
90 Job<Out_, In_ ...> job(this);
91 job.mFunc = func;
92 return job;
93 }
94
95 Async::Future<Out> result() const
96 {
97 return *reinterpret_cast<Async::Future<Out>*>(mResult);
98 }
99
100
101 void exec()
102 {
103 Async::Private::doExec<Out, In ...>(mPrev, this);
104 }
105
106private:
107 Job(JobBase *parent = nullptr)
108 : JobBase(parent)
109 {}
110
111public:
112 std::function<Async::Future<Out>(In ...)> mFunc;
113};
114
115template<typename Out, typename ... In, typename F>
116Job<Out, In ...> start(F func)
117{
118 Job<Out, In ...> job;
119 job.mFunc = std::function<Async::Future<Out>(In ...)>(func);
120 return job;
121}
122
123} // namespace Async
124
125template<typename Out, typename In>
126typename std::enable_if<!std::is_void<In>::value, void>::type
127Async::Private::doExec(JobBase *prev, JobBase *jobBase)
128{
129 prev->exec();
130 Async::Future<In> *in = reinterpret_cast<Async::Future<In>*>(prev->mResult);
131 assert(in->isFinished());
132
133 Job<Out, In> *job = dynamic_cast<Job<Out, In>*>(jobBase);
134 Async::Future<Out> *out = new Async::Future<Out>(job->mFunc(in->value()));
135 out->waitForFinished();
136 job->mResult = reinterpret_cast<void*>(out);
137};
138
139template<typename Out, typename ... In>
140typename std::enable_if<sizeof...(In) == 0, void>::type
141Async::Private::doExec(JobBase *prev, JobBase *jobBase, int * /* disambiguation */ = 0)
142{
143 if (prev) {
144 prev->exec();
145 Async::Future<void> *in = reinterpret_cast<Async::Future<void>*>(prev->mResult);
146 assert(in->isFinished());
147 }
148
149 Job<Out> *job = dynamic_cast<Job<Out>*>(jobBase);
150 Async::Future<Out> *out = new Async::Future<Out>(job->mFunc());
151 out->waitForFinished();
152 job->mResult = reinterpret_cast<void*>(out);
153};
154
155
156#endif // ASYNC_H
157
158
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 @@
1/*
2 * Copyright 2014 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License or (at your option) version 3 or any later version
8 * accepted by the membership of KDE e.V. (or its successor approved
9 * by the membership of KDE e.V.), which shall act as a proxy
10 * defined in Section 14 of version 3 of the license.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef ASYNC_IMPL_H
23#define ASYNC_IMPL_H
24
25#include "async.h"
26
27namespace Async {
28
29
30} // namespace Async
31
32#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 @@
1/*
2 * Copyright 2014 Daniel Vrátil <dvratil@redhat.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License or (at your option) version 3 or any later version
8 * accepted by the membership of KDE e.V. (or its successor approved
9 * by the membership of KDE e.V.), which shall act as a proxy
10 * defined in Section 14 of version 3 of the license.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef FUTURE_H
23#define FUTURE_H
24
25class QEventLoop;
26
27namespace Async {
28
29class FutureBase
30{
31public:
32 FutureBase();
33 FutureBase(const FutureBase &other);
34 void setFinished();
35 bool isFinished() const;
36 void waitForFinished();
37
38protected:
39 bool mFinished;
40 QEventLoop *mWaitLoop;
41};
42
43template<typename T>
44class Future : public FutureBase
45{
46public:
47 Future()
48 : FutureBase()
49 {}
50
51 Future(const Future<T> &other)
52 : FutureBase(other)
53 , mValue(other.mValue)
54 {}
55
56 Future(const T &val)
57 : FutureBase()
58 , mValue(val)
59 {}
60
61 void setValue(const T &val)
62 {
63 mValue = val;
64 }
65
66 T value() const
67 {
68 return mValue;
69 }
70
71private:
72 T mValue;
73};
74
75template<>
76class Future<void> : public FutureBase
77{
78public:
79 Future()
80 : FutureBase()
81 {}
82
83 Future(const Future<void> &other)
84 : FutureBase(other)
85 {}
86};
87
88} // namespace Async
89
90#endif // FUTURE_H