diff options
author | Dan Vrátil <dvratil@redhat.com> | 2014-12-11 11:07:04 +0100 |
---|---|---|
committer | Dan Vrátil <dvratil@redhat.com> | 2014-12-11 11:07:20 +0100 |
commit | 67d47d893bc582fbd06da8bd93a1c416fa314ca6 (patch) | |
tree | a30004b1c974baef1a700f6647eae2cf43e9f06b /async | |
parent | 0fc8477dec805f943e829a662a9e42337ce628ab (diff) | |
download | sink-67d47d893bc582fbd06da8bd93a1c416fa314ca6.tar.gz sink-67d47d893bc582fbd06da8bd93a1c416fa314ca6.zip |
Prototype of Async library
Diffstat (limited to 'async')
-rw-r--r-- | async/CMakeLists.txt | 2 | ||||
-rw-r--r-- | async/autotests/CMakeLists.txt | 5 | ||||
-rw-r--r-- | async/autotests/asynctest.cpp | 98 | ||||
-rw-r--r-- | async/src/CMakeLists.txt | 6 | ||||
-rw-r--r-- | async/src/async.cpp | 67 | ||||
-rw-r--r-- | async/src/async.h | 158 | ||||
-rw-r--r-- | async/src/async_impl.h | 32 | ||||
-rw-r--r-- | async/src/future.h | 90 |
8 files changed, 458 insertions, 0 deletions
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 @@ | |||
1 | add_subdirectory(src) | ||
2 | add_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 @@ | |||
1 | include_directories(../src ${CMAKE_CURRENT_BINARY_DIR}) | ||
2 | |||
3 | add_executable(asynctest asynctest.cpp) | ||
4 | qt5_use_modules(asynctest Test) | ||
5 | target_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 | |||
29 | class AsyncTest : public QObject | ||
30 | { | ||
31 | Q_OBJECT | ||
32 | |||
33 | public: | ||
34 | AsyncTest() | ||
35 | {} | ||
36 | |||
37 | ~AsyncTest() | ||
38 | {} | ||
39 | |||
40 | private Q_SLOTS: | ||
41 | void testSyncPromises(); | ||
42 | void testAsyncPromises(); | ||
43 | }; | ||
44 | |||
45 | void 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 | |||
73 | void 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 | |||
96 | QTEST_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 @@ | |||
1 | set(async_SRCS | ||
2 | async.cpp | ||
3 | ) | ||
4 | |||
5 | add_library(akonadi2async SHARED ${async_SRCS}) | ||
6 | 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 @@ | |||
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 | |||
29 | using namespace Async; | ||
30 | |||
31 | FutureBase::FutureBase() | ||
32 | : mFinished(false) | ||
33 | , mWaitLoop(nullptr) | ||
34 | { | ||
35 | |||
36 | } | ||
37 | |||
38 | FutureBase::FutureBase(const Async::FutureBase &other) | ||
39 | : mFinished(other.mFinished) | ||
40 | , mWaitLoop(other.mWaitLoop) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | void FutureBase::setFinished() | ||
45 | { | ||
46 | mFinished = true; | ||
47 | if (mWaitLoop && mWaitLoop->isRunning()) { | ||
48 | mWaitLoop->quit(); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | bool FutureBase::isFinished() const | ||
53 | { | ||
54 | return mFinished; | ||
55 | } | ||
56 | |||
57 | void 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 | |||
35 | namespace Async { | ||
36 | |||
37 | template<typename Out, typename ... In> | ||
38 | class Job; | ||
39 | |||
40 | template<typename Out, typename ... In> | ||
41 | Job<Out, In ...> start(const std::function<Async::Future<Out>(In ...)> &func); | ||
42 | |||
43 | |||
44 | class JobBase | ||
45 | { | ||
46 | public: | ||
47 | JobBase(JobBase *prev = nullptr) | ||
48 | : mPrev(prev) | ||
49 | , mResult(0) | ||
50 | {} | ||
51 | |||
52 | virtual void exec() = 0; | ||
53 | |||
54 | public: | ||
55 | JobBase *mPrev; | ||
56 | void *mResult; | ||
57 | }; | ||
58 | |||
59 | namespace 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 | |||
70 | template<typename Out, typename ... In> | ||
71 | class 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 | |||
79 | public: | ||
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 | |||
106 | private: | ||
107 | Job(JobBase *parent = nullptr) | ||
108 | : JobBase(parent) | ||
109 | {} | ||
110 | |||
111 | public: | ||
112 | std::function<Async::Future<Out>(In ...)> mFunc; | ||
113 | }; | ||
114 | |||
115 | template<typename Out, typename ... In, typename F> | ||
116 | Job<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 | |||
125 | template<typename Out, typename In> | ||
126 | typename std::enable_if<!std::is_void<In>::value, void>::type | ||
127 | Async::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 | |||
139 | template<typename Out, typename ... In> | ||
140 | typename std::enable_if<sizeof...(In) == 0, void>::type | ||
141 | Async::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 | |||
27 | namespace 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 | |||
25 | class QEventLoop; | ||
26 | |||
27 | namespace Async { | ||
28 | |||
29 | class FutureBase | ||
30 | { | ||
31 | public: | ||
32 | FutureBase(); | ||
33 | FutureBase(const FutureBase &other); | ||
34 | void setFinished(); | ||
35 | bool isFinished() const; | ||
36 | void waitForFinished(); | ||
37 | |||
38 | protected: | ||
39 | bool mFinished; | ||
40 | QEventLoop *mWaitLoop; | ||
41 | }; | ||
42 | |||
43 | template<typename T> | ||
44 | class Future : public FutureBase | ||
45 | { | ||
46 | public: | ||
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 | |||
71 | private: | ||
72 | T mValue; | ||
73 | }; | ||
74 | |||
75 | template<> | ||
76 | class Future<void> : public FutureBase | ||
77 | { | ||
78 | public: | ||
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 | ||