diff options
Diffstat (limited to 'async/src')
-rw-r--r-- | async/src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | async/src/async.cpp | 52 | ||||
-rw-r--r-- | async/src/async.h | 224 | ||||
-rw-r--r-- | async/src/debug.cpp | 73 | ||||
-rw-r--r-- | async/src/debug.h | 80 | ||||
-rw-r--r-- | async/src/future.cpp | 112 | ||||
-rw-r--r-- | async/src/future.h | 145 |
7 files changed, 497 insertions, 190 deletions
diff --git a/async/src/CMakeLists.txt b/async/src/CMakeLists.txt index 6f8ab63..becc8ee 100644 --- a/async/src/CMakeLists.txt +++ b/async/src/CMakeLists.txt | |||
@@ -5,6 +5,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) | |||
5 | set(async_SRCS | 5 | set(async_SRCS |
6 | async.cpp | 6 | async.cpp |
7 | future.cpp | 7 | future.cpp |
8 | debug.cpp | ||
8 | ) | 9 | ) |
9 | 10 | ||
10 | add_library(${PROJECT_NAME} SHARED ${async_SRCS}) | 11 | add_library(${PROJECT_NAME} SHARED ${async_SRCS}) |
diff --git a/async/src/async.cpp b/async/src/async.cpp index 5e26bd8..e92d333 100644 --- a/async/src/async.cpp +++ b/async/src/async.cpp | |||
@@ -21,9 +21,57 @@ | |||
21 | #include <QDebug> | 21 | #include <QDebug> |
22 | #include <QEventLoop> | 22 | #include <QEventLoop> |
23 | 23 | ||
24 | |||
25 | using namespace Async; | 24 | using namespace Async; |
26 | 25 | ||
26 | Private::Execution::Execution(const Private::ExecutorBasePtr &executor) | ||
27 | : executor(executor) | ||
28 | , resultBase(nullptr) | ||
29 | , isRunning(false) | ||
30 | , isFinished(false) | ||
31 | { | ||
32 | } | ||
33 | |||
34 | Private::Execution::~Execution() | ||
35 | { | ||
36 | if (resultBase) { | ||
37 | resultBase->releaseExecution(); | ||
38 | delete resultBase; | ||
39 | } | ||
40 | prevExecution.reset(); | ||
41 | } | ||
42 | |||
43 | void Private::Execution::setFinished() | ||
44 | { | ||
45 | isFinished = true; | ||
46 | //executor.clear(); | ||
47 | #ifndef QT_NO_DEBUG | ||
48 | if (tracer) { | ||
49 | delete tracer; | ||
50 | } | ||
51 | #endif | ||
52 | } | ||
53 | |||
54 | void Private::Execution::releaseFuture() | ||
55 | { | ||
56 | resultBase = 0; | ||
57 | } | ||
58 | |||
59 | bool Private::Execution::errorWasHandled() const | ||
60 | { | ||
61 | Execution *exec = const_cast<Execution*>(this); | ||
62 | while (exec) { | ||
63 | if (exec->executor->hasErrorFunc()) { | ||
64 | return true; | ||
65 | } | ||
66 | exec = exec->prevExecution.data(); | ||
67 | } | ||
68 | return false; | ||
69 | } | ||
70 | |||
71 | |||
72 | |||
73 | |||
74 | |||
27 | Private::ExecutorBase::ExecutorBase(const ExecutorBasePtr &parent) | 75 | Private::ExecutorBase::ExecutorBase(const ExecutorBasePtr &parent) |
28 | : mPrev(parent) | 76 | : mPrev(parent) |
29 | { | 77 | { |
@@ -34,6 +82,8 @@ Private::ExecutorBase::~ExecutorBase() | |||
34 | } | 82 | } |
35 | 83 | ||
36 | 84 | ||
85 | |||
86 | |||
37 | JobBase::JobBase(const Private::ExecutorBasePtr &executor) | 87 | JobBase::JobBase(const Private::ExecutorBasePtr &executor) |
38 | : mExecutor(executor) | 88 | : mExecutor(executor) |
39 | { | 89 | { |
diff --git a/async/src/async.h b/async/src/async.h index c6ca9e7..73eeaa0 100644 --- a/async/src/async.h +++ b/async/src/async.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <iterator> | 25 | #include <iterator> |
26 | 26 | ||
27 | #include "future.h" | 27 | #include "future.h" |
28 | #include "debug.h" | ||
28 | #include "async_impl.h" | 29 | #include "async_impl.h" |
29 | 30 | ||
30 | #include <QVector> | 31 | #include <QVector> |
@@ -46,20 +47,22 @@ | |||
46 | * that can be stored and executed later on. Jobs can be composed, similarly to functions. | 47 | * that can be stored and executed later on. Jobs can be composed, similarly to functions. |
47 | * | 48 | * |
48 | * Relations between the components: | 49 | * Relations between the components: |
49 | * * Job: description of what should happen | 50 | * * Job: API wrapper around Executors chain. Can be destroyed while still running, |
50 | * * Executor: Running execution of a job, the process that calculates the result. | 51 | * because the actual execution happens in the background |
52 | * * Executor: Describes task to execute. Executors form a linked list matching the | ||
53 | * order in which they will be executed. The Executor chain is destroyed when | ||
54 | * the parent Job is destroyed. However if the Job is still running it is | ||
55 | * guaranteed that the Executor chain will not be destroyed until the execution | ||
56 | * is finished. | ||
57 | * * Execution: The running execution of the task stored in Executor. Each call to Job::exec() | ||
58 | * instantiates new Execution chain, which makes it possible for the Job to be | ||
59 | * executed multiple times (even in parallel). | ||
51 | * * Future: Representation of the result that is being calculated | 60 | * * Future: Representation of the result that is being calculated |
52 | * | 61 | * |
53 | * Lifetime: | ||
54 | * * Before a job is executed is treated like a normal value on the stack. | ||
55 | * * As soon as the job is executed, a heap allocated executor keeps the task running until complete. The associated future handle remains | ||
56 | * valid until the task is complete. To abort a job it has to be killed through the future handle. | ||
57 | * TODO: Can we tie the lifetime of the executor to the last available future handle? | ||
58 | * | 62 | * |
59 | * TODO: Progress reporting through future | 63 | * TODO: Composed progress reporting |
60 | * TODO: Possibility to abort a job through future (perhaps optional?) | 64 | * TODO: Possibility to abort a job through future (perhaps optional?) |
61 | * TODO: Support for timeout, specified during exec call, after which the error handler gets called with a defined errorCode. | 65 | * TODO: Support for timeout, specified during exec call, after which the error handler gets called with a defined errorCode. |
62 | * TODO: Repeated execution of a job to facilitate i.e. an async while loop of a job? | ||
63 | */ | 66 | */ |
64 | namespace Async { | 67 | namespace Async { |
65 | 68 | ||
@@ -94,38 +97,18 @@ class ExecutorBase; | |||
94 | typedef QSharedPointer<ExecutorBase> ExecutorBasePtr; | 97 | typedef QSharedPointer<ExecutorBase> ExecutorBasePtr; |
95 | 98 | ||
96 | struct Execution { | 99 | struct Execution { |
97 | Execution(const ExecutorBasePtr &executor) | 100 | Execution(const ExecutorBasePtr &executor); |
98 | : executor(executor) | 101 | ~Execution(); |
99 | , resultBase(nullptr) | 102 | void setFinished(); |
100 | , isRunning(false) | ||
101 | , isFinished(false) | ||
102 | {} | ||
103 | |||
104 | ~Execution() | ||
105 | { | ||
106 | if (resultBase) { | ||
107 | resultBase->releaseExecution(); | ||
108 | delete resultBase; | ||
109 | } | ||
110 | prevExecution.reset(); | ||
111 | } | ||
112 | |||
113 | void setFinished() | ||
114 | { | ||
115 | isFinished = true; | ||
116 | executor.clear(); | ||
117 | } | ||
118 | 103 | ||
119 | template<typename T> | 104 | template<typename T> |
120 | Async::Future<T>* result() | 105 | Async::Future<T>* result() const |
121 | { | 106 | { |
122 | return static_cast<Async::Future<T>*>(resultBase); | 107 | return static_cast<Async::Future<T>*>(resultBase); |
123 | } | 108 | } |
124 | 109 | ||
125 | void releaseFuture() | 110 | void releaseFuture(); |
126 | { | 111 | bool errorWasHandled() const; |
127 | resultBase = 0; | ||
128 | } | ||
129 | 112 | ||
130 | ExecutorBasePtr executor; | 113 | ExecutorBasePtr executor; |
131 | FutureBase *resultBase; | 114 | FutureBase *resultBase; |
@@ -133,8 +116,13 @@ struct Execution { | |||
133 | bool isFinished; | 116 | bool isFinished; |
134 | 117 | ||
135 | ExecutionPtr prevExecution; | 118 | ExecutionPtr prevExecution; |
119 | |||
120 | #ifndef QT_NO_DEBUG | ||
121 | Tracer *tracer; | ||
122 | #endif | ||
136 | }; | 123 | }; |
137 | 124 | ||
125 | |||
138 | typedef QSharedPointer<Execution> ExecutionPtr; | 126 | typedef QSharedPointer<Execution> ExecutionPtr; |
139 | 127 | ||
140 | class ExecutorBase | 128 | class ExecutorBase |
@@ -145,6 +133,9 @@ class ExecutorBase | |||
145 | template<typename Out, typename ... In> | 133 | template<typename Out, typename ... In> |
146 | friend class Async::Job; | 134 | friend class Async::Job; |
147 | 135 | ||
136 | friend class Execution; | ||
137 | friend class Async::Tracer; | ||
138 | |||
148 | public: | 139 | public: |
149 | virtual ~ExecutorBase(); | 140 | virtual ~ExecutorBase(); |
150 | virtual ExecutionPtr exec(const ExecutorBasePtr &self) = 0; | 141 | virtual ExecutionPtr exec(const ExecutorBasePtr &self) = 0; |
@@ -155,21 +146,31 @@ protected: | |||
155 | template<typename T> | 146 | template<typename T> |
156 | Async::Future<T>* createFuture(const ExecutionPtr &execution) const; | 147 | Async::Future<T>* createFuture(const ExecutionPtr &execution) const; |
157 | 148 | ||
149 | virtual bool hasErrorFunc() const = 0; | ||
150 | virtual bool handleError(const ExecutionPtr &execution) = 0; | ||
151 | |||
158 | ExecutorBasePtr mPrev; | 152 | ExecutorBasePtr mPrev; |
153 | |||
154 | #ifndef QT_NO_DEBUG | ||
155 | QString mExecutorName; | ||
156 | #endif | ||
159 | }; | 157 | }; |
160 | 158 | ||
161 | template<typename PrevOut, typename Out, typename ... In> | 159 | template<typename PrevOut, typename Out, typename ... In> |
162 | class Executor : public ExecutorBase | 160 | class Executor : public ExecutorBase |
163 | { | 161 | { |
164 | protected: | 162 | protected: |
165 | Executor(ErrorHandler errorHandler, const Private::ExecutorBasePtr &parent) | 163 | Executor(ErrorHandler errorFunc, const Private::ExecutorBasePtr &parent) |
166 | : ExecutorBase(parent) | 164 | : ExecutorBase(parent) |
167 | , mErrorFunc(errorHandler) | 165 | , mErrorFunc(errorFunc) |
168 | {} | 166 | {} |
167 | |||
169 | virtual ~Executor() {} | 168 | virtual ~Executor() {} |
170 | virtual void run(const ExecutionPtr &execution) = 0; | 169 | virtual void run(const ExecutionPtr &execution) = 0; |
171 | 170 | ||
172 | ExecutionPtr exec(const ExecutorBasePtr &self); | 171 | ExecutionPtr exec(const ExecutorBasePtr &self); |
172 | bool hasErrorFunc() const { return (bool) mErrorFunc; } | ||
173 | bool handleError(const ExecutionPtr &execution); | ||
173 | 174 | ||
174 | std::function<void(int, const QString &)> mErrorFunc; | 175 | std::function<void(int, const QString &)> mErrorFunc; |
175 | }; | 176 | }; |
@@ -178,7 +179,7 @@ template<typename Out, typename ... In> | |||
178 | class ThenExecutor: public Executor<typename detail::prevOut<In ...>::type, Out, In ...> | 179 | class ThenExecutor: public Executor<typename detail::prevOut<In ...>::type, Out, In ...> |
179 | { | 180 | { |
180 | public: | 181 | public: |
181 | ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler errorHandler, const ExecutorBasePtr &parent); | 182 | ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler errorFunc, const ExecutorBasePtr &parent); |
182 | void run(const ExecutionPtr &execution); | 183 | void run(const ExecutionPtr &execution); |
183 | private: | 184 | private: |
184 | ThenTask<Out, In ...> mFunc; | 185 | ThenTask<Out, In ...> mFunc; |
@@ -188,7 +189,7 @@ template<typename PrevOut, typename Out, typename In> | |||
188 | class EachExecutor : public Executor<PrevOut, Out, In> | 189 | class EachExecutor : public Executor<PrevOut, Out, In> |
189 | { | 190 | { |
190 | public: | 191 | public: |
191 | EachExecutor(EachTask<Out, In> each, ErrorHandler errorHandler, const ExecutorBasePtr &parent); | 192 | EachExecutor(EachTask<Out, In> each, ErrorHandler errorFunc, const ExecutorBasePtr &parent); |
192 | void run(const ExecutionPtr &execution); | 193 | void run(const ExecutionPtr &execution); |
193 | private: | 194 | private: |
194 | EachTask<Out, In> mFunc; | 195 | EachTask<Out, In> mFunc; |
@@ -199,7 +200,7 @@ template<typename Out, typename In> | |||
199 | class ReduceExecutor : public ThenExecutor<Out, In> | 200 | class ReduceExecutor : public ThenExecutor<Out, In> |
200 | { | 201 | { |
201 | public: | 202 | public: |
202 | ReduceExecutor(ReduceTask<Out, In> reduce, ErrorHandler errorHandler, const ExecutorBasePtr &parent); | 203 | ReduceExecutor(ReduceTask<Out, In> reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent); |
203 | private: | 204 | private: |
204 | ReduceTask<Out, In> mFunc; | 205 | ReduceTask<Out, In> mFunc; |
205 | }; | 206 | }; |
@@ -208,7 +209,7 @@ template<typename Out, typename ... In> | |||
208 | class SyncThenExecutor : public Executor<typename detail::prevOut<In ...>::type, Out, In ...> | 209 | class SyncThenExecutor : public Executor<typename detail::prevOut<In ...>::type, Out, In ...> |
209 | { | 210 | { |
210 | public: | 211 | public: |
211 | SyncThenExecutor(SyncThenTask<Out, In ...> then, ErrorHandler errorHandler, const ExecutorBasePtr &parent); | 212 | SyncThenExecutor(SyncThenTask<Out, In ...> then, ErrorHandler errorFunc, const ExecutorBasePtr &parent); |
212 | void run(const ExecutionPtr &execution); | 213 | void run(const ExecutionPtr &execution); |
213 | 214 | ||
214 | private: | 215 | private: |
@@ -221,7 +222,7 @@ template<typename Out, typename In> | |||
221 | class SyncReduceExecutor : public SyncThenExecutor<Out, In> | 222 | class SyncReduceExecutor : public SyncThenExecutor<Out, In> |
222 | { | 223 | { |
223 | public: | 224 | public: |
224 | SyncReduceExecutor(SyncReduceTask<Out, In> reduce, ErrorHandler errorHandler, const ExecutorBasePtr &parent); | 225 | SyncReduceExecutor(SyncReduceTask<Out, In> reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent); |
225 | private: | 226 | private: |
226 | SyncReduceTask<Out, In> mFunc; | 227 | SyncReduceTask<Out, In> mFunc; |
227 | }; | 228 | }; |
@@ -230,7 +231,7 @@ template<typename PrevOut, typename Out, typename In> | |||
230 | class SyncEachExecutor : public Executor<PrevOut, Out, In> | 231 | class SyncEachExecutor : public Executor<PrevOut, Out, In> |
231 | { | 232 | { |
232 | public: | 233 | public: |
233 | SyncEachExecutor(SyncEachTask<Out, In> each, ErrorHandler errorHandler, const ExecutorBasePtr &parent); | 234 | SyncEachExecutor(SyncEachTask<Out, In> each, ErrorHandler errorFunc, const ExecutorBasePtr &parent); |
234 | void run(const ExecutionPtr &execution); | 235 | void run(const ExecutionPtr &execution); |
235 | private: | 236 | private: |
236 | void run(Async::Future<Out> *future, const typename PrevOut::value_type &arg, std::false_type); // !std::is_void<Out> | 237 | void run(Async::Future<Out> *future, const typename PrevOut::value_type &arg, std::false_type); // !std::is_void<Out> |
@@ -251,10 +252,10 @@ private: | |||
251 | * where @p In is type of the result. | 252 | * where @p In is type of the result. |
252 | */ | 253 | */ |
253 | template<typename Out, typename ... In> | 254 | template<typename Out, typename ... In> |
254 | Job<Out, In ...> start(ThenTask<Out, In ...> func); | 255 | Job<Out, In ...> start(ThenTask<Out, In ...> func, ErrorHandler errorFunc = ErrorHandler()); |
255 | 256 | ||
256 | template<typename Out, typename ... In> | 257 | template<typename Out, typename ... In> |
257 | Job<Out, In ...> start(SyncThenTask<Out, In ...> func); | 258 | Job<Out, In ...> start(SyncThenTask<Out, In ...> func, ErrorHandler errorFunc = ErrorHandler()); |
258 | 259 | ||
259 | #ifdef WITH_KJOB | 260 | #ifdef WITH_KJOB |
260 | template<typename ReturnType, typename KJobType, ReturnType (KJobType::*KJobResultMethod)(), typename ... Args> | 261 | template<typename ReturnType, typename KJobType, ReturnType (KJobType::*KJobResultMethod)(), typename ... Args> |
@@ -356,10 +357,10 @@ class Job : public JobBase | |||
356 | friend class Job; | 357 | friend class Job; |
357 | 358 | ||
358 | template<typename OutOther, typename ... InOther> | 359 | template<typename OutOther, typename ... InOther> |
359 | friend Job<OutOther, InOther ...> start(Async::ThenTask<OutOther, InOther ...> func); | 360 | friend Job<OutOther, InOther ...> start(Async::ThenTask<OutOther, InOther ...> func, ErrorHandler errorFunc); |
360 | 361 | ||
361 | template<typename OutOther, typename ... InOther> | 362 | template<typename OutOther, typename ... InOther> |
362 | friend Job<OutOther, InOther ...> start(Async::SyncThenTask<OutOther, InOther ...> func); | 363 | friend Job<OutOther, InOther ...> start(Async::SyncThenTask<OutOther, InOther ...> func, ErrorHandler errorFunc); |
363 | 364 | ||
364 | #ifdef WITH_KJOB | 365 | #ifdef WITH_KJOB |
365 | template<typename ReturnType, typename KJobType, ReturnType (KJobType::*KJobResultMethod)(), typename ... Args> | 366 | template<typename ReturnType, typename KJobType, ReturnType (KJobType::*KJobResultMethod)(), typename ... Args> |
@@ -499,9 +500,14 @@ private: | |||
499 | auto job = otherJob; | 500 | auto job = otherJob; |
500 | FutureWatcher<OutOther> *watcher = new FutureWatcher<OutOther>(); | 501 | FutureWatcher<OutOther> *watcher = new FutureWatcher<OutOther>(); |
501 | QObject::connect(watcher, &FutureWatcherBase::futureReady, | 502 | QObject::connect(watcher, &FutureWatcherBase::futureReady, |
502 | [watcher, &future]() { | 503 | [watcher, future]() { |
503 | Async::detail::copyFutureValue(watcher->future(), future); | 504 | // FIXME: We pass future by value, because using reference causes the |
504 | future.setFinished(); | 505 | // future to get deleted before this lambda is invoked, leading to crash |
506 | // in copyFutureValue() | ||
507 | // copy by value is const | ||
508 | auto outFuture = future; | ||
509 | Async::detail::copyFutureValue(watcher->future(), outFuture); | ||
510 | outFuture.setFinished(); | ||
505 | delete watcher; | 511 | delete watcher; |
506 | }); | 512 | }); |
507 | watcher->setFuture(job.exec(in ...)); | 513 | watcher->setFuture(job.exec(in ...)); |
@@ -517,17 +523,17 @@ private: | |||
517 | namespace Async { | 523 | namespace Async { |
518 | 524 | ||
519 | template<typename Out, typename ... In> | 525 | template<typename Out, typename ... In> |
520 | Job<Out, In ...> start(ThenTask<Out, In ...> func) | 526 | Job<Out, In ...> start(ThenTask<Out, In ...> func, ErrorHandler error) |
521 | { | 527 | { |
522 | return Job<Out, In...>(Private::ExecutorBasePtr( | 528 | return Job<Out, In...>(Private::ExecutorBasePtr( |
523 | new Private::ThenExecutor<Out, In ...>(func, ErrorHandler(), Private::ExecutorBasePtr()))); | 529 | new Private::ThenExecutor<Out, In ...>(func, error, Private::ExecutorBasePtr()))); |
524 | } | 530 | } |
525 | 531 | ||
526 | template<typename Out, typename ... In> | 532 | template<typename Out, typename ... In> |
527 | Job<Out, In ...> start(SyncThenTask<Out, In ...> func) | 533 | Job<Out, In ...> start(SyncThenTask<Out, In ...> func, ErrorHandler error) |
528 | { | 534 | { |
529 | return Job<Out, In...>(Private::ExecutorBasePtr( | 535 | return Job<Out, In...>(Private::ExecutorBasePtr( |
530 | new Private::SyncThenExecutor<Out, In ...>(func, ErrorHandler(), Private::ExecutorBasePtr()))); | 536 | new Private::SyncThenExecutor<Out, In ...>(func, error, Private::ExecutorBasePtr()))); |
531 | } | 537 | } |
532 | 538 | ||
533 | #ifdef WITH_KJOB | 539 | #ifdef WITH_KJOB |
@@ -586,20 +592,18 @@ ExecutionPtr Executor<PrevOut, Out, In ...>::exec(const ExecutorBasePtr &self) | |||
586 | // Passing 'self' to execution ensures that the Executor chain remains | 592 | // Passing 'self' to execution ensures that the Executor chain remains |
587 | // valid until the entire execution is finished | 593 | // valid until the entire execution is finished |
588 | ExecutionPtr execution = ExecutionPtr::create(self); | 594 | ExecutionPtr execution = ExecutionPtr::create(self); |
595 | #ifndef QT_NO_DEBUG | ||
596 | execution->tracer = new Tracer(execution.data()); // owned by execution | ||
597 | #endif | ||
589 | 598 | ||
590 | // chainup | 599 | // chainup |
591 | execution->prevExecution = mPrev ? mPrev->exec(mPrev) : ExecutionPtr(); | 600 | execution->prevExecution = mPrev ? mPrev->exec(mPrev) : ExecutionPtr(); |
592 | /* | ||
593 | } else if (mPrev && !mPrevFuture) { | ||
594 | // If previous job is running or finished, just get it's future | ||
595 | mPrevFuture = static_cast<Async::Future<PrevOut>*>(mPrev->result()); | ||
596 | } | ||
597 | */ | ||
598 | 601 | ||
599 | execution->resultBase = this->createFuture<Out>(execution); | 602 | execution->resultBase = ExecutorBase::createFuture<Out>(execution); |
600 | auto fw = new Async::FutureWatcher<Out>(); | 603 | auto fw = new Async::FutureWatcher<Out>(); |
601 | QObject::connect(fw, &Async::FutureWatcher<Out>::futureReady, | 604 | QObject::connect(fw, &Async::FutureWatcher<Out>::futureReady, |
602 | [fw, execution, this]() { | 605 | [fw, execution, this]() { |
606 | handleError(execution); | ||
603 | execution->setFinished(); | 607 | execution->setFinished(); |
604 | delete fw; | 608 | delete fw; |
605 | }); | 609 | }); |
@@ -607,50 +611,77 @@ ExecutionPtr Executor<PrevOut, Out, In ...>::exec(const ExecutorBasePtr &self) | |||
607 | 611 | ||
608 | Async::Future<PrevOut> *prevFuture = execution->prevExecution ? execution->prevExecution->result<PrevOut>() : nullptr; | 612 | Async::Future<PrevOut> *prevFuture = execution->prevExecution ? execution->prevExecution->result<PrevOut>() : nullptr; |
609 | if (!prevFuture || prevFuture->isFinished()) { | 613 | if (!prevFuture || prevFuture->isFinished()) { |
610 | if (prevFuture && prevFuture->errorCode() != 0) { | 614 | if (prevFuture) { // prevFuture implies execution->prevExecution |
611 | if (mErrorFunc) { | 615 | if (prevFuture->errorCode()) { |
612 | mErrorFunc(prevFuture->errorCode(), prevFuture->errorMessage()); | 616 | // Propagate the errorCode and message to the outer Future |
613 | execution->resultBase->setFinished(); | 617 | execution->resultBase->setError(prevFuture->errorCode(), prevFuture->errorMessage()); |
614 | execution->setFinished(); | 618 | if (!execution->errorWasHandled()) { |
615 | return execution; | 619 | if (handleError(execution)) { |
620 | return execution; | ||
621 | } | ||
622 | } else { | ||
623 | return execution; | ||
624 | } | ||
616 | } else { | 625 | } else { |
617 | // Propagate the error to next caller | 626 | // Propagate error (if any) |
618 | } | 627 | } |
619 | } | 628 | } |
629 | |||
620 | execution->isRunning = true; | 630 | execution->isRunning = true; |
621 | run(execution); | 631 | run(execution); |
622 | } else { | 632 | } else { |
623 | auto futureWatcher = new Async::FutureWatcher<PrevOut>(); | 633 | auto prevFutureWatcher = new Async::FutureWatcher<PrevOut>(); |
624 | QObject::connect(futureWatcher, &Async::FutureWatcher<PrevOut>::futureReady, | 634 | QObject::connect(prevFutureWatcher, &Async::FutureWatcher<PrevOut>::futureReady, |
625 | [futureWatcher, execution, this]() { | 635 | [prevFutureWatcher, execution, this]() { |
626 | auto prevFuture = futureWatcher->future(); | 636 | auto prevFuture = prevFutureWatcher->future(); |
627 | assert(prevFuture.isFinished()); | 637 | assert(prevFuture.isFinished()); |
628 | delete futureWatcher; | 638 | delete prevFutureWatcher; |
629 | if (prevFuture.errorCode() != 0) { | 639 | auto prevExecutor = execution->executor->mPrev; |
630 | if (mErrorFunc) { | 640 | if (prevFuture.errorCode()) { |
631 | mErrorFunc(prevFuture.errorCode(), prevFuture.errorMessage()); | 641 | execution->resultBase->setError(prevFuture.errorCode(), prevFuture.errorMessage()); |
632 | execution->resultBase->setFinished(); | 642 | if (!execution->errorWasHandled()) { |
633 | return; | 643 | if (handleError(execution)) { |
644 | return; | ||
645 | } | ||
634 | } else { | 646 | } else { |
635 | // Propagate the error to next caller | 647 | return; |
636 | } | 648 | } |
637 | } | 649 | } |
650 | |||
651 | |||
652 | // propagate error (if any) | ||
638 | execution->isRunning = true; | 653 | execution->isRunning = true; |
639 | run(execution); | 654 | run(execution); |
640 | }); | 655 | }); |
641 | 656 | ||
642 | futureWatcher->setFuture(*static_cast<Async::Future<PrevOut>*>(prevFuture)); | 657 | prevFutureWatcher->setFuture(*static_cast<Async::Future<PrevOut>*>(prevFuture)); |
643 | } | 658 | } |
644 | 659 | ||
645 | return execution; | 660 | return execution; |
646 | } | 661 | } |
647 | 662 | ||
663 | template<typename PrevOut, typename Out, typename ... In> | ||
664 | bool Executor<PrevOut, Out, In ...>::handleError(const ExecutionPtr &execution) | ||
665 | { | ||
666 | assert(execution->resultBase->isFinished()); | ||
667 | if (execution->resultBase->errorCode()) { | ||
668 | if (mErrorFunc) { | ||
669 | mErrorFunc(execution->resultBase->errorCode(), | ||
670 | execution->resultBase->errorMessage()); | ||
671 | return true; | ||
672 | } | ||
673 | } | ||
674 | |||
675 | return false; | ||
676 | } | ||
677 | |||
648 | 678 | ||
649 | template<typename Out, typename ... In> | 679 | template<typename Out, typename ... In> |
650 | ThenExecutor<Out, In ...>::ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler error, const ExecutorBasePtr &parent) | 680 | ThenExecutor<Out, In ...>::ThenExecutor(ThenTask<Out, In ...> then, ErrorHandler error, const ExecutorBasePtr &parent) |
651 | : Executor<typename detail::prevOut<In ...>::type, Out, In ...>(error, parent) | 681 | : Executor<typename detail::prevOut<In ...>::type, Out, In ...>(error, parent) |
652 | , mFunc(then) | 682 | , mFunc(then) |
653 | { | 683 | { |
684 | STORE_EXECUTOR_NAME("ThenExecutor", Out, In ...); | ||
654 | } | 685 | } |
655 | 686 | ||
656 | template<typename Out, typename ... In> | 687 | template<typename Out, typename ... In> |
@@ -662,7 +693,7 @@ void ThenExecutor<Out, In ...>::run(const ExecutionPtr &execution) | |||
662 | assert(prevFuture->isFinished()); | 693 | assert(prevFuture->isFinished()); |
663 | } | 694 | } |
664 | 695 | ||
665 | this->mFunc(prevFuture ? prevFuture->value() : In() ..., *execution->result<Out>()); | 696 | ThenExecutor<Out, In ...>::mFunc(prevFuture ? prevFuture->value() : In() ..., *execution->result<Out>()); |
666 | } | 697 | } |
667 | 698 | ||
668 | template<typename PrevOut, typename Out, typename In> | 699 | template<typename PrevOut, typename Out, typename In> |
@@ -670,6 +701,7 @@ EachExecutor<PrevOut, Out, In>::EachExecutor(EachTask<Out, In> each, ErrorHandle | |||
670 | : Executor<PrevOut, Out, In>(error, parent) | 701 | : Executor<PrevOut, Out, In>(error, parent) |
671 | , mFunc(each) | 702 | , mFunc(each) |
672 | { | 703 | { |
704 | STORE_EXECUTOR_NAME("EachExecutor", PrevOut, Out, In); | ||
673 | } | 705 | } |
674 | 706 | ||
675 | template<typename PrevOut, typename Out, typename In> | 707 | template<typename PrevOut, typename Out, typename In> |
@@ -687,7 +719,7 @@ void EachExecutor<PrevOut, Out, In>::run(const ExecutionPtr &execution) | |||
687 | 719 | ||
688 | for (auto arg : prevFuture->value()) { | 720 | for (auto arg : prevFuture->value()) { |
689 | Async::Future<Out> future; | 721 | Async::Future<Out> future; |
690 | this->mFunc(arg, future); | 722 | EachExecutor<PrevOut, Out, In>::mFunc(arg, future); |
691 | auto fw = new Async::FutureWatcher<Out>(); | 723 | auto fw = new Async::FutureWatcher<Out>(); |
692 | mFutureWatchers.append(fw); | 724 | mFutureWatchers.append(fw); |
693 | QObject::connect(fw, &Async::FutureWatcher<Out>::futureReady, | 725 | QObject::connect(fw, &Async::FutureWatcher<Out>::futureReady, |
@@ -708,16 +740,18 @@ void EachExecutor<PrevOut, Out, In>::run(const ExecutionPtr &execution) | |||
708 | } | 740 | } |
709 | 741 | ||
710 | template<typename Out, typename In> | 742 | template<typename Out, typename In> |
711 | ReduceExecutor<Out, In>::ReduceExecutor(ReduceTask<Out, In> reduce, ErrorHandler error, const ExecutorBasePtr &parent) | 743 | ReduceExecutor<Out, In>::ReduceExecutor(ReduceTask<Out, In> reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent) |
712 | : ThenExecutor<Out, In>(reduce, error, parent) | 744 | : ThenExecutor<Out, In>(reduce, errorFunc, parent) |
713 | { | 745 | { |
746 | STORE_EXECUTOR_NAME("ReduceExecutor", Out, In); | ||
714 | } | 747 | } |
715 | 748 | ||
716 | template<typename Out, typename ... In> | 749 | template<typename Out, typename ... In> |
717 | SyncThenExecutor<Out, In ...>::SyncThenExecutor(SyncThenTask<Out, In ...> then, ErrorHandler errorHandler, const ExecutorBasePtr &parent) | 750 | SyncThenExecutor<Out, In ...>::SyncThenExecutor(SyncThenTask<Out, In ...> then, ErrorHandler errorFunc, const ExecutorBasePtr &parent) |
718 | : Executor<typename detail::prevOut<In ...>::type, Out, In ...>(errorHandler, parent) | 751 | : Executor<typename detail::prevOut<In ...>::type, Out, In ...>(errorFunc, parent) |
719 | , mFunc(then) | 752 | , mFunc(then) |
720 | { | 753 | { |
754 | STORE_EXECUTOR_NAME("SyncThenExecutor", Out, In ...); | ||
721 | } | 755 | } |
722 | 756 | ||
723 | template<typename Out, typename ... In> | 757 | template<typename Out, typename ... In> |
@@ -740,7 +774,7 @@ void SyncThenExecutor<Out, In ...>::run(const ExecutionPtr &execution, std::fals | |||
740 | : nullptr; | 774 | : nullptr; |
741 | (void) prevFuture; // silence 'set but not used' warning | 775 | (void) prevFuture; // silence 'set but not used' warning |
742 | Async::Future<Out> *future = execution->result<Out>(); | 776 | Async::Future<Out> *future = execution->result<Out>(); |
743 | future->setValue(this->mFunc(prevFuture ? prevFuture->value() : In() ...)); | 777 | future->setValue(SyncThenExecutor<Out, In...>::mFunc(prevFuture ? prevFuture->value() : In() ...)); |
744 | } | 778 | } |
745 | 779 | ||
746 | template<typename Out, typename ... In> | 780 | template<typename Out, typename ... In> |
@@ -751,14 +785,15 @@ void SyncThenExecutor<Out, In ...>::run(const ExecutionPtr &execution, std::true | |||
751 | ? execution->prevExecution->result<typename detail::prevOut<In ...>::type>() | 785 | ? execution->prevExecution->result<typename detail::prevOut<In ...>::type>() |
752 | : nullptr; | 786 | : nullptr; |
753 | (void) prevFuture; // silence 'set but not used' warning | 787 | (void) prevFuture; // silence 'set but not used' warning |
754 | this->mFunc(prevFuture ? prevFuture->value() : In() ...); | 788 | SyncThenExecutor<Out, In ...>::mFunc(prevFuture ? prevFuture->value() : In() ...); |
755 | } | 789 | } |
756 | 790 | ||
757 | template<typename PrevOut, typename Out, typename In> | 791 | template<typename PrevOut, typename Out, typename In> |
758 | SyncEachExecutor<PrevOut, Out, In>::SyncEachExecutor(SyncEachTask<Out, In> each, ErrorHandler errorHandler, const ExecutorBasePtr &parent) | 792 | SyncEachExecutor<PrevOut, Out, In>::SyncEachExecutor(SyncEachTask<Out, In> each, ErrorHandler errorFunc, const ExecutorBasePtr &parent) |
759 | : Executor<PrevOut, Out, In>(errorHandler, parent) | 793 | : Executor<PrevOut, Out, In>(errorFunc, parent) |
760 | , mFunc(each) | 794 | , mFunc(each) |
761 | { | 795 | { |
796 | STORE_EXECUTOR_NAME("SyncEachExecutor", PrevOut, Out, In); | ||
762 | } | 797 | } |
763 | 798 | ||
764 | template<typename PrevOut, typename Out, typename In> | 799 | template<typename PrevOut, typename Out, typename In> |
@@ -783,19 +818,20 @@ void SyncEachExecutor<PrevOut, Out, In>::run(const ExecutionPtr &execution) | |||
783 | template<typename PrevOut, typename Out, typename In> | 818 | template<typename PrevOut, typename Out, typename In> |
784 | void SyncEachExecutor<PrevOut, Out, In>::run(Async::Future<Out> *out, const typename PrevOut::value_type &arg, std::false_type) | 819 | void SyncEachExecutor<PrevOut, Out, In>::run(Async::Future<Out> *out, const typename PrevOut::value_type &arg, std::false_type) |
785 | { | 820 | { |
786 | out->setValue(out->value() + this->mFunc(arg)); | 821 | out->setValue(out->value() + SyncEachExecutor<PrevOut, Out, In>::mFunc(arg)); |
787 | } | 822 | } |
788 | 823 | ||
789 | template<typename PrevOut, typename Out, typename In> | 824 | template<typename PrevOut, typename Out, typename In> |
790 | void SyncEachExecutor<PrevOut, Out, In>::run(Async::Future<Out> * /* unused */, const typename PrevOut::value_type &arg, std::true_type) | 825 | void SyncEachExecutor<PrevOut, Out, In>::run(Async::Future<Out> * /* unused */, const typename PrevOut::value_type &arg, std::true_type) |
791 | { | 826 | { |
792 | this->mFunc(arg); | 827 | SyncEachExecutor<PrevOut, Out, In>::mFunc(arg); |
793 | } | 828 | } |
794 | 829 | ||
795 | template<typename Out, typename In> | 830 | template<typename Out, typename In> |
796 | SyncReduceExecutor<Out, In>::SyncReduceExecutor(SyncReduceTask<Out, In> reduce, ErrorHandler errorHandler, const ExecutorBasePtr &parent) | 831 | SyncReduceExecutor<Out, In>::SyncReduceExecutor(SyncReduceTask<Out, In> reduce, ErrorHandler errorFunc, const ExecutorBasePtr &parent) |
797 | : SyncThenExecutor<Out, In>(reduce, errorHandler, parent) | 832 | : SyncThenExecutor<Out, In>(reduce, errorFunc, parent) |
798 | { | 833 | { |
834 | STORE_EXECUTOR_NAME("SyncReduceExecutor", Out, In); | ||
799 | } | 835 | } |
800 | 836 | ||
801 | 837 | ||
diff --git a/async/src/debug.cpp b/async/src/debug.cpp new file mode 100644 index 0000000..9dfad1a --- /dev/null +++ b/async/src/debug.cpp | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Daniel Vrátil <dvratil@redhat.com> | ||
3 | * | ||
4 | * This library is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU Library General Public License as | ||
6 | * published by the Free Software Foundation; either version 2 of | ||
7 | * the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This library is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU Library General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU Library General Public License | ||
15 | * along with this library. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include "debug.h" | ||
19 | #include "async.h" | ||
20 | |||
21 | #include <QStringBuilder> | ||
22 | |||
23 | #ifdef __GNUG__ | ||
24 | #include <cxxabi.h> | ||
25 | #include <memory> | ||
26 | #endif | ||
27 | |||
28 | namespace Async | ||
29 | { | ||
30 | |||
31 | Q_LOGGING_CATEGORY(Debug, "org.kde.async", QtWarningMsg); | ||
32 | Q_LOGGING_CATEGORY(Trace, "org.kde.async.trace", QtWarningMsg); | ||
33 | |||
34 | QString demangleName(const char *name) | ||
35 | { | ||
36 | #ifdef __GNUG__ | ||
37 | int status = 1; // uses -3 to 0 error codes | ||
38 | std::unique_ptr<char, void(*)(void*)> demangled(abi::__cxa_demangle(name, 0, 0, &status), std::free); | ||
39 | if (status == 0) { | ||
40 | return QString(demangled.get()); | ||
41 | } | ||
42 | #endif | ||
43 | return QString(name); | ||
44 | } | ||
45 | |||
46 | } | ||
47 | |||
48 | using namespace Async; | ||
49 | |||
50 | int Tracer::lastId = 0; | ||
51 | |||
52 | Tracer::Tracer(Private::Execution *execution) | ||
53 | : mId(lastId++) | ||
54 | , mExecution(execution) | ||
55 | { | ||
56 | msg(Async::Tracer::Start); | ||
57 | } | ||
58 | |||
59 | Tracer::~Tracer() | ||
60 | { | ||
61 | msg(Async::Tracer::End); | ||
62 | // FIXME: Does this work on parallel executions? | ||
63 | --lastId; | ||
64 | --mId; | ||
65 | } | ||
66 | |||
67 | void Tracer::msg(Tracer::MsgType msgType) | ||
68 | { | ||
69 | qCDebug(Trace).nospace() << (QString().fill(QLatin1Char(' '), mId * 2) % | ||
70 | (msgType == Async::Tracer::Start ? " START " : " END ") % | ||
71 | QString::number(mId) % " " % | ||
72 | mExecution->executor->mExecutorName); | ||
73 | } | ||
diff --git a/async/src/debug.h b/async/src/debug.h new file mode 100644 index 0000000..c453eb3 --- /dev/null +++ b/async/src/debug.h | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Copyright 2015 Daniel Vrátil <dvratil@redhat.com> | ||
3 | * | ||
4 | * This library is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU Library General Public License as | ||
6 | * published by the Free Software Foundation; either version 2 of | ||
7 | * the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This library is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU Library General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU Library General Public License | ||
15 | * along with this library. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef ASYNC_DEBUG_H | ||
19 | #define ASYNC_DEBUG_H | ||
20 | |||
21 | #include <QLoggingCategory> | ||
22 | #include <QStringBuilder> | ||
23 | |||
24 | #ifndef QT_NO_DEBUG | ||
25 | #include <typeinfo> | ||
26 | #endif | ||
27 | |||
28 | namespace Async | ||
29 | { | ||
30 | |||
31 | Q_DECLARE_LOGGING_CATEGORY(Debug) | ||
32 | Q_DECLARE_LOGGING_CATEGORY(Trace) | ||
33 | |||
34 | QString demangleName(const char *name); | ||
35 | |||
36 | namespace Private | ||
37 | { | ||
38 | class Execution; | ||
39 | } | ||
40 | |||
41 | class Tracer | ||
42 | { | ||
43 | public: | ||
44 | Tracer(Private::Execution *execution); | ||
45 | ~Tracer(); | ||
46 | |||
47 | private: | ||
48 | enum MsgType { | ||
49 | Start, | ||
50 | End | ||
51 | }; | ||
52 | void msg(MsgType); | ||
53 | |||
54 | int mId; | ||
55 | Private::Execution *mExecution; | ||
56 | |||
57 | static int lastId; | ||
58 | }; | ||
59 | |||
60 | } | ||
61 | |||
62 | #ifndef QT_NO_DEBUG | ||
63 | template<typename T> | ||
64 | QString storeExecutorNameExpanded() { | ||
65 | return Async::demangleName(typeid(T).name()); | ||
66 | } | ||
67 | |||
68 | template<typename T, typename ... Tail> | ||
69 | typename std::enable_if<sizeof ... (Tail) != 0, QString>::type | ||
70 | storeExecutorNameExpanded() { | ||
71 | return storeExecutorNameExpanded<T>() % QStringLiteral(", ") % storeExecutorNameExpanded<Tail ...>(); | ||
72 | } | ||
73 | |||
74 | #define STORE_EXECUTOR_NAME(name, ...) \ | ||
75 | ExecutorBase::mExecutorName = QStringLiteral(name) % QStringLiteral("<") % storeExecutorNameExpanded<__VA_ARGS__>() % QStringLiteral(">") | ||
76 | #else | ||
77 | #define STORE_EXECUTOR_NAME(...) | ||
78 | #endif | ||
79 | |||
80 | #endif // ASYNC_DEBUG_H \ No newline at end of file | ||
diff --git a/async/src/future.cpp b/async/src/future.cpp index 50a326a..4f3cd80 100644 --- a/async/src/future.cpp +++ b/async/src/future.cpp | |||
@@ -20,11 +20,41 @@ | |||
20 | 20 | ||
21 | using namespace Async; | 21 | using namespace Async; |
22 | 22 | ||
23 | FutureBase::PrivateBase::PrivateBase(const Private::ExecutionPtr &execution) | ||
24 | : finished(false) | ||
25 | , errorCode(0) | ||
26 | , mExecution(execution) | ||
27 | { | ||
28 | } | ||
29 | |||
30 | FutureBase::PrivateBase::~PrivateBase() | ||
31 | { | ||
32 | Private::ExecutionPtr executionPtr = mExecution.toStrongRef(); | ||
33 | if (executionPtr) { | ||
34 | executionPtr->releaseFuture(); | ||
35 | releaseExecution(); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | void FutureBase::PrivateBase::releaseExecution() | ||
40 | { | ||
41 | mExecution.clear(); | ||
42 | } | ||
43 | |||
44 | |||
45 | |||
23 | FutureBase::FutureBase() | 46 | FutureBase::FutureBase() |
47 | : d(nullptr) | ||
48 | { | ||
49 | } | ||
50 | |||
51 | FutureBase::FutureBase(FutureBase::PrivateBase *dd) | ||
52 | : d(dd) | ||
24 | { | 53 | { |
25 | } | 54 | } |
26 | 55 | ||
27 | FutureBase::FutureBase(const Async::FutureBase &other) | 56 | FutureBase::FutureBase(const Async::FutureBase &other) |
57 | : d(other.d) | ||
28 | { | 58 | { |
29 | } | 59 | } |
30 | 60 | ||
@@ -32,35 +62,97 @@ FutureBase::~FutureBase() | |||
32 | { | 62 | { |
33 | } | 63 | } |
34 | 64 | ||
35 | FutureBase::PrivateBase::PrivateBase(const Private::ExecutionPtr &execution) | 65 | void FutureBase::releaseExecution() |
36 | : mExecution(execution) | ||
37 | { | 66 | { |
67 | d->releaseExecution(); | ||
38 | } | 68 | } |
39 | 69 | ||
40 | FutureBase::PrivateBase::~PrivateBase() | 70 | void FutureBase::setFinished() |
41 | { | 71 | { |
42 | Private::ExecutionPtr executionPtr = mExecution.toStrongRef(); | 72 | if (isFinished()) { |
43 | if (executionPtr) { | 73 | return; |
44 | executionPtr->releaseFuture(); | 74 | } |
45 | releaseExecution(); | 75 | d->finished = true; |
76 | for (auto watcher : d->watchers) { | ||
77 | if (watcher) { | ||
78 | watcher->futureReadyCallback(); | ||
79 | } | ||
46 | } | 80 | } |
47 | } | 81 | } |
48 | 82 | ||
49 | void FutureBase::PrivateBase::releaseExecution() | 83 | bool FutureBase::isFinished() const |
50 | { | 84 | { |
51 | mExecution.clear(); | 85 | return d->finished; |
86 | } | ||
87 | |||
88 | void FutureBase::setError(int code, const QString &message) | ||
89 | { | ||
90 | d->errorCode = code; | ||
91 | d->errorMessage = message; | ||
92 | setFinished(); | ||
93 | } | ||
94 | |||
95 | int FutureBase::errorCode() const | ||
96 | { | ||
97 | return d->errorCode; | ||
98 | } | ||
99 | |||
100 | QString FutureBase::errorMessage() const | ||
101 | { | ||
102 | return d->errorMessage; | ||
103 | } | ||
104 | |||
105 | void FutureBase::setProgress(int processed, int total) | ||
106 | { | ||
107 | setProgress((qreal) processed / total); | ||
108 | } | ||
109 | |||
110 | void FutureBase::setProgress(qreal progress) | ||
111 | { | ||
112 | for (auto watcher : d->watchers) { | ||
113 | if (watcher) { | ||
114 | watcher->futureProgressCallback(progress); | ||
115 | } | ||
116 | } | ||
52 | } | 117 | } |
53 | 118 | ||
54 | 119 | ||
55 | 120 | ||
121 | void FutureBase::addWatcher(FutureWatcherBase* watcher) | ||
122 | { | ||
123 | d->watchers.append(QPointer<FutureWatcherBase>(watcher)); | ||
124 | } | ||
125 | |||
126 | |||
127 | |||
128 | |||
129 | |||
56 | FutureWatcherBase::FutureWatcherBase(QObject *parent) | 130 | FutureWatcherBase::FutureWatcherBase(QObject *parent) |
57 | : QObject(parent) | 131 | : QObject(parent) |
132 | , d(new FutureWatcherBase::Private) | ||
58 | { | 133 | { |
59 | } | 134 | } |
60 | 135 | ||
61 | FutureWatcherBase::~FutureWatcherBase() | 136 | FutureWatcherBase::~FutureWatcherBase() |
62 | { | 137 | { |
138 | delete d; | ||
63 | } | 139 | } |
64 | 140 | ||
141 | void FutureWatcherBase::futureReadyCallback() | ||
142 | { | ||
143 | Q_EMIT futureReady(); | ||
144 | } | ||
145 | |||
146 | void FutureWatcherBase::futureProgressCallback(qreal progress) | ||
147 | { | ||
148 | Q_EMIT futureProgress(progress); | ||
149 | } | ||
65 | 150 | ||
66 | #include "future.moc" | 151 | void FutureWatcherBase::setFutureImpl(const FutureBase &future) |
152 | { | ||
153 | d->future = future; | ||
154 | d->future.addWatcher(this); | ||
155 | if (future.isFinished()) { | ||
156 | futureReadyCallback(); | ||
157 | } | ||
158 | } | ||
diff --git a/async/src/future.h b/async/src/future.h index cadd96d..ff199ef 100644 --- a/async/src/future.h +++ b/async/src/future.h | |||
@@ -29,28 +29,35 @@ class QEventLoop; | |||
29 | 29 | ||
30 | namespace Async { | 30 | namespace Async { |
31 | 31 | ||
32 | class FutureWatcherBase; | ||
33 | template<typename T> | ||
34 | class FutureWatcher; | ||
35 | |||
32 | namespace Private { | 36 | namespace Private { |
33 | class Execution; | 37 | class Execution; |
34 | class ExecutorBase; | 38 | class ExecutorBase; |
35 | 39 | ||
36 | typedef QSharedPointer<Execution> ExecutionPtr; | 40 | typedef QSharedPointer<Execution> ExecutionPtr; |
37 | 41 | } // namespace Private | |
38 | } | ||
39 | 42 | ||
40 | class FutureBase | 43 | class FutureBase |
41 | { | 44 | { |
42 | friend class Async::Private::Execution; | 45 | friend class Async::Private::Execution; |
46 | friend class FutureWatcherBase; | ||
43 | 47 | ||
44 | public: | 48 | public: |
45 | virtual ~FutureBase(); | 49 | virtual ~FutureBase(); |
46 | 50 | ||
47 | virtual void setFinished() = 0; | 51 | void setFinished(); |
48 | virtual bool isFinished() const = 0; | 52 | bool isFinished() const; |
49 | virtual void setError(int code = 1, const QString &message = QString()) = 0; | 53 | void setError(int code = 1, const QString &message = QString()); |
54 | int errorCode() const; | ||
55 | QString errorMessage() const; | ||
50 | 56 | ||
51 | protected: | 57 | void setProgress(qreal progress); |
52 | virtual void releaseExecution() = 0; | 58 | void setProgress(int processed, int total); |
53 | 59 | ||
60 | protected: | ||
54 | class PrivateBase : public QSharedData | 61 | class PrivateBase : public QSharedData |
55 | { | 62 | { |
56 | public: | 63 | public: |
@@ -59,12 +66,24 @@ protected: | |||
59 | 66 | ||
60 | void releaseExecution(); | 67 | void releaseExecution(); |
61 | 68 | ||
69 | bool finished; | ||
70 | int errorCode; | ||
71 | QString errorMessage; | ||
72 | |||
73 | QVector<QPointer<FutureWatcherBase>> watchers; | ||
62 | private: | 74 | private: |
63 | QWeakPointer<Async::Private::Execution> mExecution; | 75 | QWeakPointer<Async::Private::Execution> mExecution; |
64 | }; | 76 | }; |
65 | 77 | ||
66 | FutureBase(); | 78 | FutureBase(); |
79 | FutureBase(FutureBase::PrivateBase *dd); | ||
67 | FutureBase(const FutureBase &other); | 80 | FutureBase(const FutureBase &other); |
81 | |||
82 | void addWatcher(Async::FutureWatcherBase *watcher); | ||
83 | void releaseExecution(); | ||
84 | |||
85 | protected: | ||
86 | QExplicitlySharedDataPointer<PrivateBase> d; | ||
68 | }; | 87 | }; |
69 | 88 | ||
70 | template<typename T> | 89 | template<typename T> |
@@ -79,42 +98,7 @@ class FutureGeneric : public FutureBase | |||
79 | friend class FutureWatcher<T>; | 98 | friend class FutureWatcher<T>; |
80 | 99 | ||
81 | public: | 100 | public: |
82 | void setFinished() | 101 | void waitForFinished() const |
83 | { | ||
84 | if (d->finished) { | ||
85 | return; | ||
86 | } | ||
87 | d->finished = true; | ||
88 | for (auto watcher : d->watchers) { | ||
89 | if (watcher) { | ||
90 | watcher->futureReadyCallback(); | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
95 | bool isFinished() const | ||
96 | { | ||
97 | return d->finished; | ||
98 | } | ||
99 | |||
100 | void setError(int errorCode, const QString &message) | ||
101 | { | ||
102 | d->errorCode = errorCode; | ||
103 | d->errorMessage = message; | ||
104 | setFinished(); | ||
105 | } | ||
106 | |||
107 | int errorCode() const | ||
108 | { | ||
109 | return d->errorCode; | ||
110 | } | ||
111 | |||
112 | QString errorMessage() const | ||
113 | { | ||
114 | return d->errorMessage; | ||
115 | } | ||
116 | |||
117 | void waitForFinished() | ||
118 | { | 102 | { |
119 | if (isFinished()) { | 103 | if (isFinished()) { |
120 | return; | 104 | return; |
@@ -123,52 +107,33 @@ public: | |||
123 | QEventLoop eventLoop; | 107 | QEventLoop eventLoop; |
124 | QObject::connect(&watcher, &Async::FutureWatcher<T>::futureReady, | 108 | QObject::connect(&watcher, &Async::FutureWatcher<T>::futureReady, |
125 | &eventLoop, &QEventLoop::quit); | 109 | &eventLoop, &QEventLoop::quit); |
126 | watcher.setFuture(*static_cast<Async::Future<T>*>(this)); | 110 | watcher.setFuture(*static_cast<const Async::Future<T>*>(this)); |
127 | eventLoop.exec(); | 111 | eventLoop.exec(); |
128 | } | 112 | } |
129 | 113 | ||
130 | protected: | 114 | protected: |
131 | FutureGeneric(const Async::Private::ExecutionPtr &execution) | 115 | FutureGeneric(const Async::Private::ExecutionPtr &execution) |
132 | : FutureBase() | 116 | : FutureBase(new Private(execution)) |
133 | , d(new Private(execution)) | ||
134 | {} | 117 | {} |
135 | 118 | ||
136 | FutureGeneric(const FutureGeneric<T> &other) | 119 | FutureGeneric(const FutureGeneric<T> &other) |
137 | : FutureBase(other) | 120 | : FutureBase(other) |
138 | , d(other.d) | ||
139 | {} | 121 | {} |
140 | 122 | ||
123 | protected: | ||
141 | class Private : public FutureBase::PrivateBase | 124 | class Private : public FutureBase::PrivateBase |
142 | { | 125 | { |
143 | public: | 126 | public: |
144 | Private(const Async::Private::ExecutionPtr &execution) | 127 | Private(const Async::Private::ExecutionPtr &execution) |
145 | : FutureBase::PrivateBase(execution) | 128 | : FutureBase::PrivateBase(execution) |
146 | , finished(false) | ||
147 | , errorCode(0) | ||
148 | {} | 129 | {} |
149 | 130 | ||
150 | typename std::conditional<std::is_void<T>::value, int /* dummy */, T>::type | 131 | typename std::conditional<std::is_void<T>::value, int /* dummy */, T>::type |
151 | value; | 132 | value; |
152 | |||
153 | QVector<QPointer<FutureWatcher<T>>> watchers; | ||
154 | bool finished; | ||
155 | int errorCode; | ||
156 | QString errorMessage; | ||
157 | }; | 133 | }; |
158 | |||
159 | QExplicitlySharedDataPointer<Private> d; | ||
160 | |||
161 | void releaseExecution() | ||
162 | { | ||
163 | d->releaseExecution(); | ||
164 | } | ||
165 | |||
166 | void addWatcher(FutureWatcher<T> *watcher) | ||
167 | { | ||
168 | d->watchers.append(QPointer<FutureWatcher<T>>(watcher)); | ||
169 | } | ||
170 | }; | 134 | }; |
171 | 135 | ||
136 | |||
172 | template<typename T> | 137 | template<typename T> |
173 | class Future : public FutureGeneric<T> | 138 | class Future : public FutureGeneric<T> |
174 | { | 139 | { |
@@ -188,12 +153,12 @@ public: | |||
188 | 153 | ||
189 | void setValue(const T &value) | 154 | void setValue(const T &value) |
190 | { | 155 | { |
191 | this->d->value = value; | 156 | static_cast<typename FutureGeneric<T>::Private*>(this->d.data())->value = value; |
192 | } | 157 | } |
193 | 158 | ||
194 | T value() const | 159 | T value() const |
195 | { | 160 | { |
196 | return this->d->value; | 161 | return static_cast<typename FutureGeneric<T>::Private*>(this->d.data())->value; |
197 | } | 162 | } |
198 | 163 | ||
199 | protected: | 164 | protected: |
@@ -208,9 +173,6 @@ class Future<void> : public FutureGeneric<void> | |||
208 | { | 173 | { |
209 | friend class Async::Private::ExecutorBase; | 174 | friend class Async::Private::ExecutorBase; |
210 | 175 | ||
211 | template<typename T_> | ||
212 | friend class Async::FutureWatcher; | ||
213 | |||
214 | public: | 176 | public: |
215 | Future() | 177 | Future() |
216 | : FutureGeneric<void>(Async::Private::ExecutionPtr()) | 178 | : FutureGeneric<void>(Async::Private::ExecutionPtr()) |
@@ -227,16 +189,38 @@ protected: | |||
227 | }; | 189 | }; |
228 | 190 | ||
229 | 191 | ||
192 | |||
193 | |||
194 | |||
230 | class FutureWatcherBase : public QObject | 195 | class FutureWatcherBase : public QObject |
231 | { | 196 | { |
232 | Q_OBJECT | 197 | Q_OBJECT |
233 | 198 | ||
199 | friend class FutureBase; | ||
200 | |||
201 | Q_SIGNALS: | ||
202 | void futureReady(); | ||
203 | void futureProgress(qreal progress); | ||
204 | |||
234 | protected: | 205 | protected: |
235 | FutureWatcherBase(QObject *parent = nullptr); | 206 | FutureWatcherBase(QObject *parent = nullptr); |
236 | virtual ~FutureWatcherBase(); | 207 | virtual ~FutureWatcherBase(); |
237 | 208 | ||
238 | Q_SIGNALS: | 209 | void futureReadyCallback(); |
239 | void futureReady(); | 210 | void futureProgressCallback(qreal progress); |
211 | |||
212 | void setFutureImpl(const Async::FutureBase &future); | ||
213 | |||
214 | protected: | ||
215 | class Private { | ||
216 | public: | ||
217 | Async::FutureBase future; | ||
218 | }; | ||
219 | |||
220 | Private * const d; | ||
221 | |||
222 | private: | ||
223 | Q_DISABLE_COPY(FutureWatcherBase); | ||
240 | }; | 224 | }; |
241 | 225 | ||
242 | template<typename T> | 226 | template<typename T> |
@@ -254,25 +238,16 @@ public: | |||
254 | 238 | ||
255 | void setFuture(const Async::Future<T> &future) | 239 | void setFuture(const Async::Future<T> &future) |
256 | { | 240 | { |
257 | mFuture = future; | 241 | setFutureImpl(*static_cast<const Async::FutureBase*>(&future)); |
258 | mFuture.addWatcher(this); | ||
259 | if (future.isFinished()) { | ||
260 | futureReadyCallback(); | ||
261 | } | ||
262 | } | 242 | } |
263 | 243 | ||
264 | Async::Future<T> future() const | 244 | Async::Future<T> future() const |
265 | { | 245 | { |
266 | return mFuture; | 246 | return *static_cast<Async::Future<T>*>(&d->future); |
267 | } | 247 | } |
268 | 248 | ||
269 | private: | 249 | private: |
270 | void futureReadyCallback() | 250 | Q_DISABLE_COPY(FutureWatcher<T>); |
271 | { | ||
272 | Q_EMIT futureReady(); | ||
273 | } | ||
274 | |||
275 | Async::Future<T> mFuture; | ||
276 | }; | 251 | }; |
277 | 252 | ||
278 | } // namespace Async | 253 | } // namespace Async |