diff options
author | Dan Vrátil <dvratil@redhat.com> | 2015-03-30 15:47:45 +0200 |
---|---|---|
committer | Dan Vrátil <dvratil@redhat.com> | 2015-03-30 15:47:45 +0200 |
commit | 1d946c166cc7a4a2556e8bfaab7dc66695b555e1 (patch) | |
tree | d51e2fd0cb83867243813feb4ea4ecace3ef2e60 | |
parent | 3b8ebe6d4235f5ba12bc9c9854a6dd28cbff06b5 (diff) | |
download | sink-1d946c166cc7a4a2556e8bfaab7dc66695b555e1.tar.gz sink-1d946c166cc7a4a2556e8bfaab7dc66695b555e1.zip |
Async: allow consumer continuation without arguments
It is now possible to chain a job that takes no arguments after a job
that returns void.
Unfortunatelly it is not yet possible to disregard return value of a
previous job.
-rw-r--r-- | async/autotests/asynctest.cpp | 95 | ||||
-rw-r--r-- | async/src/async.h | 37 |
2 files changed, 124 insertions, 8 deletions
diff --git a/async/autotests/asynctest.cpp b/async/autotests/asynctest.cpp index 7437608..1074ff0 100644 --- a/async/autotests/asynctest.cpp +++ b/async/autotests/asynctest.cpp | |||
@@ -48,18 +48,20 @@ private Q_SLOTS: | |||
48 | void testAsyncThen(); | 48 | void testAsyncThen(); |
49 | void testSyncThen(); | 49 | void testSyncThen(); |
50 | void testJoinedThen(); | 50 | void testJoinedThen(); |
51 | void testVoidThen(); | ||
51 | 52 | ||
52 | void testAsyncEach(); | 53 | void testAsyncEach(); |
53 | void testSyncEach(); | 54 | void testSyncEach(); |
54 | void testJoinedEach(); | 55 | void testJoinedEach(); |
56 | void testVoidEach(); | ||
55 | 57 | ||
56 | void testAsyncReduce(); | 58 | void testAsyncReduce(); |
57 | void testSyncReduce(); | 59 | void testSyncReduce(); |
58 | void testJoinedReduce(); | 60 | void testJoinedReduce(); |
61 | void testVoidReduce(); | ||
59 | 62 | ||
60 | void testErrorHandler(); | 63 | void testErrorHandler(); |
61 | 64 | ||
62 | |||
63 | void testChainingRunningJob(); | 65 | void testChainingRunningJob(); |
64 | void testChainingFinishedJob(); | 66 | void testChainingFinishedJob(); |
65 | 67 | ||
@@ -94,6 +96,30 @@ private: | |||
94 | }; | 96 | }; |
95 | 97 | ||
96 | 98 | ||
99 | template<> | ||
100 | class AsyncTest::AsyncSimulator<void> { | ||
101 | public: | ||
102 | AsyncSimulator(Async::Future<void> &future) | ||
103 | : mFuture(future) | ||
104 | { | ||
105 | QObject::connect(&mTimer, &QTimer::timeout, | ||
106 | [this]() { | ||
107 | mFuture.setFinished(); | ||
108 | }); | ||
109 | QObject::connect(&mTimer, &QTimer::timeout, | ||
110 | [this]() { | ||
111 | delete this; | ||
112 | }); | ||
113 | mTimer.setSingleShot(true); | ||
114 | mTimer.start(200); | ||
115 | } | ||
116 | |||
117 | private: | ||
118 | Async::Future<void> mFuture; | ||
119 | QTimer mTimer; | ||
120 | }; | ||
121 | |||
122 | |||
97 | 123 | ||
98 | void AsyncTest::testSyncPromises() | 124 | void AsyncTest::testSyncPromises() |
99 | { | 125 | { |
@@ -213,7 +239,8 @@ void AsyncTest::testSyncThen() | |||
213 | auto job = Async::start<int>( | 239 | auto job = Async::start<int>( |
214 | []() -> int { | 240 | []() -> int { |
215 | return 42; | 241 | return 42; |
216 | }).then<int, int>( | 242 | }) |
243 | .then<int, int>( | ||
217 | [](int in) -> int { | 244 | [](int in) -> int { |
218 | return in * 2; | 245 | return in * 2; |
219 | }); | 246 | }); |
@@ -243,6 +270,32 @@ void AsyncTest::testJoinedThen() | |||
243 | QCOMPARE(future.value(), 84); | 270 | QCOMPARE(future.value(), 84); |
244 | } | 271 | } |
245 | 272 | ||
273 | void AsyncTest::testVoidThen() | ||
274 | { | ||
275 | int check = 0; | ||
276 | |||
277 | auto job = Async::start<void>( | ||
278 | [&check](Async::Future<void> &future) { | ||
279 | new AsyncSimulator<void>(future); | ||
280 | ++check; | ||
281 | }) | ||
282 | .then<void>( | ||
283 | [&check](Async::Future<void> &future) { | ||
284 | new AsyncSimulator<void>(future); | ||
285 | ++check; | ||
286 | }) | ||
287 | .then<void>( | ||
288 | [&check]() { | ||
289 | ++check; | ||
290 | }); | ||
291 | |||
292 | auto future = job.exec(); | ||
293 | future.waitForFinished(); | ||
294 | |||
295 | QVERIFY(future.isFinished()); | ||
296 | QCOMPARE(check, 3); | ||
297 | } | ||
298 | |||
246 | 299 | ||
247 | 300 | ||
248 | void AsyncTest::testAsyncEach() | 301 | void AsyncTest::testAsyncEach() |
@@ -303,6 +356,25 @@ void AsyncTest::testJoinedEach() | |||
303 | QCOMPARE(future.value(), expected); | 356 | QCOMPARE(future.value(), expected); |
304 | } | 357 | } |
305 | 358 | ||
359 | void AsyncTest::testVoidEach() | ||
360 | { | ||
361 | QList<int> check; | ||
362 | auto job = Async::start<QList<int>>( | ||
363 | []() -> QList<int> { | ||
364 | return { 1, 2, 3, 4 }; | ||
365 | }).each<void, int>( | ||
366 | [&check](const int &v) { | ||
367 | check << v; | ||
368 | }); | ||
369 | |||
370 | auto future = job.exec(); | ||
371 | |||
372 | const QList<int> expected({ 1, 2, 3, 4 }); | ||
373 | QVERIFY(future.isFinished()); | ||
374 | QCOMPARE(check, expected); | ||
375 | } | ||
376 | |||
377 | |||
306 | 378 | ||
307 | 379 | ||
308 | 380 | ||
@@ -377,6 +449,23 @@ void AsyncTest::testJoinedReduce() | |||
377 | QCOMPARE(future.value(), 10); | 449 | QCOMPARE(future.value(), 10); |
378 | } | 450 | } |
379 | 451 | ||
452 | void AsyncTest::testVoidReduce() | ||
453 | { | ||
454 | // This must not compile (reduce with void result makes no sense) | ||
455 | #ifdef TEST_BUILD_FAIL | ||
456 | auto job = Async::start<QList<int>>( | ||
457 | []() -> QList<int> { | ||
458 | return { 1, 2, 3, 4 }; | ||
459 | }) | ||
460 | .reduce<void, QList<int>>( | ||
461 | [](const QList<int> &list) -> int { | ||
462 | return; | ||
463 | }); | ||
464 | |||
465 | auto future = job.exec(); | ||
466 | QVERIFY(future.isFinished()); | ||
467 | #endif | ||
468 | } | ||
380 | 469 | ||
381 | 470 | ||
382 | 471 | ||
@@ -471,8 +560,6 @@ void AsyncTest::testChainingFinishedJob() | |||
471 | 560 | ||
472 | 561 | ||
473 | 562 | ||
474 | |||
475 | |||
476 | void AsyncTest::benchmarkSyncThenExecutor() | 563 | void AsyncTest::benchmarkSyncThenExecutor() |
477 | { | 564 | { |
478 | auto job = Async::start<int>( | 565 | auto job = Async::start<int>( |
diff --git a/async/src/async.h b/async/src/async.h index 8296fbc..2be1260 100644 --- a/async/src/async.h +++ b/async/src/async.h | |||
@@ -150,7 +150,10 @@ class SyncThenExecutor : public Executor<typename detail::prevOut<In ...>::type, | |||
150 | public: | 150 | public: |
151 | SyncThenExecutor(SyncThenTask<Out, In ...> then, ErrorHandler errorHandler, const ExecutorBasePtr &parent); | 151 | SyncThenExecutor(SyncThenTask<Out, In ...> then, ErrorHandler errorHandler, const ExecutorBasePtr &parent); |
152 | void previousFutureReady(); | 152 | void previousFutureReady(); |
153 | |||
153 | private: | 154 | private: |
155 | void run(std::false_type); // !std::is_void<Out> | ||
156 | void run(std::true_type); // std::is_void<Out> | ||
154 | SyncThenTask<Out, In ...> mFunc; | 157 | SyncThenTask<Out, In ...> mFunc; |
155 | }; | 158 | }; |
156 | 159 | ||
@@ -170,6 +173,8 @@ public: | |||
170 | SyncEachExecutor(SyncEachTask<Out, In> each, ErrorHandler errorHandler, const ExecutorBasePtr &parent); | 173 | SyncEachExecutor(SyncEachTask<Out, In> each, ErrorHandler errorHandler, const ExecutorBasePtr &parent); |
171 | void previousFutureReady(); | 174 | void previousFutureReady(); |
172 | private: | 175 | private: |
176 | void run(Async::Future<Out> *future, const typename PrevOut::value_type &arg, std::false_type); // !std::is_void<Out> | ||
177 | void run(Async::Future<Out> *future, const typename PrevOut::value_type &arg, std::true_type); // std::is_void<Out> | ||
173 | SyncEachTask<Out, In> mFunc; | 178 | SyncEachTask<Out, In> mFunc; |
174 | }; | 179 | }; |
175 | 180 | ||
@@ -386,8 +391,8 @@ private: | |||
386 | { | 391 | { |
387 | static_assert(detail::isIterable<Out>::value, | 392 | static_assert(detail::isIterable<Out>::value, |
388 | "The 'Each' task can only be connected to a job that returns a list or an array."); | 393 | "The 'Each' task can only be connected to a job that returns a list or an array."); |
389 | static_assert(detail::isIterable<OutOther>::value, | 394 | static_assert(std::is_void<OutOther>::value || detail::isIterable<OutOther>::value, |
390 | "The result type of 'Each' task must be a list or an array."); | 395 | "The result type of 'Each' task must be void, a list or an array."); |
391 | } | 396 | } |
392 | 397 | ||
393 | template<typename InOther> | 398 | template<typename InOther> |
@@ -603,9 +608,21 @@ void SyncThenExecutor<Out, In ...>::previousFutureReady() | |||
603 | assert(this->mPrevFuture->isFinished()); | 608 | assert(this->mPrevFuture->isFinished()); |
604 | } | 609 | } |
605 | 610 | ||
611 | run(std::is_void<Out>()); | ||
612 | this->mResult->setFinished(); | ||
613 | } | ||
614 | |||
615 | template<typename Out, typename ... In> | ||
616 | void SyncThenExecutor<Out, In ...>::run(std::false_type) | ||
617 | { | ||
606 | Out result = this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ...); | 618 | Out result = this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ...); |
607 | static_cast<Async::Future<Out>*>(this->mResult)->setValue(result); | 619 | static_cast<Async::Future<Out>*>(this->mResult)->setValue(result); |
608 | this->mResult->setFinished(); | 620 | } |
621 | |||
622 | template<typename Out, typename ... In> | ||
623 | void SyncThenExecutor<Out, In ...>::run(std::true_type) | ||
624 | { | ||
625 | this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ...); | ||
609 | } | 626 | } |
610 | 627 | ||
611 | template<typename PrevOut, typename Out, typename In> | 628 | template<typename PrevOut, typename Out, typename In> |
@@ -626,11 +643,23 @@ void SyncEachExecutor<PrevOut, Out, In>::previousFutureReady() | |||
626 | } | 643 | } |
627 | 644 | ||
628 | for (auto arg : this->mPrevFuture->value()) { | 645 | for (auto arg : this->mPrevFuture->value()) { |
629 | out->setValue(out->value() + this->mFunc(arg)); | 646 | run(out, arg, std::is_void<Out>()); |
630 | } | 647 | } |
631 | out->setFinished(); | 648 | out->setFinished(); |
632 | } | 649 | } |
633 | 650 | ||
651 | template<typename PrevOut, typename Out, typename In> | ||
652 | void SyncEachExecutor<PrevOut, Out, In>::run(Async::Future<Out> *out, const typename PrevOut::value_type &arg, std::false_type) | ||
653 | { | ||
654 | out->setValue(out->value() + this->mFunc(arg)); | ||
655 | } | ||
656 | |||
657 | template<typename PrevOut, typename Out, typename In> | ||
658 | void SyncEachExecutor<PrevOut, Out, In>::run(Async::Future<Out> * /* unushed */, const typename PrevOut::value_type &arg, std::true_type) | ||
659 | { | ||
660 | this->mFunc(arg); | ||
661 | } | ||
662 | |||
634 | template<typename Out, typename In> | 663 | template<typename Out, typename In> |
635 | SyncReduceExecutor<Out, In>::SyncReduceExecutor(SyncReduceTask<Out, In> reduce, ErrorHandler errorHandler, const ExecutorBasePtr &parent) | 664 | SyncReduceExecutor<Out, In>::SyncReduceExecutor(SyncReduceTask<Out, In> reduce, ErrorHandler errorHandler, const ExecutorBasePtr &parent) |
636 | : SyncThenExecutor<Out, In>(reduce, errorHandler, parent) | 665 | : SyncThenExecutor<Out, In>(reduce, errorHandler, parent) |