summaryrefslogtreecommitdiffstats
path: root/common/resultprovider.h
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2015-04-30 15:34:15 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2015-04-30 15:34:15 +0200
commit6b12a5df6289921a55f26665cf83bf290154f8b9 (patch)
tree64bb7cae28a227b68173cdaa7e7bea8dfe24d928 /common/resultprovider.h
parent9bc2e107c49f3cd983e68c5453851221d5096979 (diff)
downloadsink-6b12a5df6289921a55f26665cf83bf290154f8b9.tar.gz
sink-6b12a5df6289921a55f26665cf83bf290154f8b9.zip
Moved resultprovider to separate file.
Diffstat (limited to 'common/resultprovider.h')
-rw-r--r--common/resultprovider.h221
1 files changed, 221 insertions, 0 deletions
diff --git a/common/resultprovider.h b/common/resultprovider.h
new file mode 100644
index 0000000..4d985d9
--- /dev/null
+++ b/common/resultprovider.h
@@ -0,0 +1,221 @@
1/*
2 * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) version 3, or any
8 * later version accepted by the membership of KDE e.V. (or its
9 * successor approved by the membership of KDE e.V.), which shall
10 * act as a proxy defined in Section 6 of version 3 of the license.
11 *
12 * This library 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 GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#pragma once
22
23#include <functional>
24#include <memory>
25#include "threadboundary.h"
26
27namespace async {
28
29/**
30* Query result set
31*/
32template<class T>
33class ResultEmitter;
34
35/*
36* The promise side for the result emitter
37*/
38template<class T>
39class ResultProvider {
40private:
41 void callInMainThreadOnEmitter(void (ResultEmitter<T>::*f)())
42 {
43 //We use the eventloop to call the addHandler directly from the main eventloop.
44 //That way the result emitter implementation doesn't have to care about threadsafety at all.
45 //The alternative would be to make all handlers of the emitter threadsafe.
46 if (auto emitter = mResultEmitter.toStrongRef()) {
47 auto weakEmitter = mResultEmitter;
48 //We don't want to keep the emitter alive here, so we only capture a weak reference
49 emitter->mThreadBoundary.callInMainThread([weakEmitter, f]() {
50 if (auto strongRef = weakEmitter.toStrongRef()) {
51 (strongRef.data()->*f)();
52 }
53 });
54 }
55 }
56
57 void callInMainThreadOnEmitter(const std::function<void()> &f)
58 {
59 //We use the eventloop to call the addHandler directly from the main eventloop.
60 //That way the result emitter implementation doesn't have to care about threadsafety at all.
61 //The alternative would be to make all handlers of the emitter threadsafe.
62 if (auto emitter = mResultEmitter.toStrongRef()) {
63 emitter->mThreadBoundary.callInMainThread([f]() {
64 f();
65 });
66 }
67 }
68
69public:
70 //Called from worker thread
71 void add(const T &value)
72 {
73 //Because I don't know how to use bind
74 auto weakEmitter = mResultEmitter;
75 callInMainThreadOnEmitter([weakEmitter, value](){
76 if (auto strongRef = weakEmitter.toStrongRef()) {
77 strongRef->addHandler(value);
78 }
79 });
80 }
81
82 void initialResultSetComplete()
83 {
84 callInMainThreadOnEmitter(&ResultEmitter<T>::initialResultSetComplete);
85 }
86
87 //Called from worker thread
88 void complete()
89 {
90 callInMainThreadOnEmitter(&ResultEmitter<T>::complete);
91 }
92
93 void clear()
94 {
95 callInMainThreadOnEmitter(&ResultEmitter<T>::clear);
96 }
97
98
99 QSharedPointer<ResultEmitter<T> > emitter()
100 {
101 if (!mResultEmitter) {
102 //We have to go over a separate var and return that, otherwise we'd delete the emitter immediately again
103 auto sharedPtr = QSharedPointer<ResultEmitter<T> >(new ResultEmitter<T>, [this](ResultEmitter<T> *emitter){ done(); delete emitter; });
104 mResultEmitter = sharedPtr;
105 return sharedPtr;
106 }
107
108 return mResultEmitter.toStrongRef();
109 }
110
111 /**
112 * For lifetimemanagement only.
113 * We keep the runner alive as long as the result provider exists.
114 */
115 void setQueryRunner(const QSharedPointer<QObject> &runner)
116 {
117 mQueryRunner = runner;
118 }
119
120 /**
121 * For lifetimemanagement only.
122 * We keep the runner alive as long as the result provider exists.
123 */
124 void setFacade(const std::shared_ptr<void> &facade)
125 {
126 mFacade = facade;
127 }
128
129 void onDone(const std::function<void()> &callback)
130 {
131 mOnDoneCallback = callback;
132 }
133
134 bool isDone() const
135 {
136 //The existance of the emitter currently defines wether we're done or not.
137 return mResultEmitter.toStrongRef().isNull();
138 }
139
140private:
141 void done()
142 {
143 qWarning() << "done";
144 if (mOnDoneCallback) {
145 mOnDoneCallback();
146 mOnDoneCallback = std::function<void()>();
147 }
148 }
149
150 QWeakPointer<ResultEmitter<T> > mResultEmitter;
151 QSharedPointer<QObject> mQueryRunner;
152 std::shared_ptr<void> mFacade;
153 std::function<void()> mOnDoneCallback;
154};
155
156/*
157* The future side for the client.
158*
159* It does not directly hold the state.
160*
161* The advantage of this is that we can specialize it to:
162* * do inline transformations to the data
163* * directly store the state in a suitable datastructure: QList, QSet, std::list, QVector, ...
164* * build async interfaces with signals
165* * build sync interfaces that block when accessing the value
166*
167*/
168template<class DomainType>
169class ResultEmitter {
170public:
171 void onAdded(const std::function<void(const DomainType&)> &handler)
172 {
173 addHandler = handler;
174 }
175 // void onRemoved(const std::function<void(const T&)> &handler);
176 void onInitialResultSetComplete(const std::function<void(void)> &handler)
177 {
178 initialResultSetCompleteHandler = handler;
179 }
180 void onComplete(const std::function<void(void)> &handler)
181 {
182 completeHandler = handler;
183 }
184 void onClear(const std::function<void(void)> &handler)
185 {
186 clearHandler = handler;
187 }
188
189 void add(const DomainType &value)
190 {
191 addHandler(value);
192 }
193
194 void initialResultSetComplete()
195 {
196 initialResultSetCompleteHandler();
197 }
198
199 void complete()
200 {
201 completeHandler();
202 }
203
204 void clear()
205 {
206 clearHandler();
207 }
208
209private:
210 friend class ResultProvider<DomainType>;
211
212 std::function<void(const DomainType&)> addHandler;
213 // std::function<void(const T&)> removeHandler;
214 std::function<void(void)> initialResultSetCompleteHandler;
215 std::function<void(void)> completeHandler;
216 std::function<void(void)> clearHandler;
217 ThreadBoundary mThreadBoundary;
218};
219
220}
221