summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Vrátil <dvratil@redhat.com>2015-03-30 15:47:45 +0200
committerDan Vrátil <dvratil@redhat.com>2015-03-30 15:47:45 +0200
commit1d946c166cc7a4a2556e8bfaab7dc66695b555e1 (patch)
treed51e2fd0cb83867243813feb4ea4ecace3ef2e60
parent3b8ebe6d4235f5ba12bc9c9854a6dd28cbff06b5 (diff)
downloadsink-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.cpp95
-rw-r--r--async/src/async.h37
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
99template<>
100class AsyncTest::AsyncSimulator<void> {
101public:
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
117private:
118 Async::Future<void> mFuture;
119 QTimer mTimer;
120};
121
122
97 123
98void AsyncTest::testSyncPromises() 124void 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
273void 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
248void AsyncTest::testAsyncEach() 301void AsyncTest::testAsyncEach()
@@ -303,6 +356,25 @@ void AsyncTest::testJoinedEach()
303 QCOMPARE(future.value(), expected); 356 QCOMPARE(future.value(), expected);
304} 357}
305 358
359void 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
452void 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
476void AsyncTest::benchmarkSyncThenExecutor() 563void 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,
150public: 150public:
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
153private: 154private:
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();
172private: 175private:
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
615template<typename Out, typename ... In>
616void 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
622template<typename Out, typename ... In>
623void SyncThenExecutor<Out, In ...>::run(std::true_type)
624{
625 this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ...);
609} 626}
610 627
611template<typename PrevOut, typename Out, typename In> 628template<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
651template<typename PrevOut, typename Out, typename In>
652void 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
657template<typename PrevOut, typename Out, typename In>
658void 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
634template<typename Out, typename In> 663template<typename Out, typename In>
635SyncReduceExecutor<Out, In>::SyncReduceExecutor(SyncReduceTask<Out, In> reduce, ErrorHandler errorHandler, const ExecutorBasePtr &parent) 664SyncReduceExecutor<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)