From 1aee1bda9fc81c888ad18fea107c271133dd5442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Thu, 11 Dec 2014 14:22:27 +0100 Subject: Async: change syntax of callables We now pass our own Async::Future to each task, instead of expecting tasks to return their future. This allows us to re-use the same Future for repeated invocations, like in the Each task. --- async/autotests/asynctest.cpp | 36 ++++++++++++++++++--------- async/src/async.h | 58 +++++++++++++++++++++++++++++-------------- async/src/async_impl.h | 21 +++++++++++++++- 3 files changed, 83 insertions(+), 32 deletions(-) (limited to 'async') diff --git a/async/autotests/asynctest.cpp b/async/autotests/asynctest.cpp index 786ff3c..19e40f7 100644 --- a/async/autotests/asynctest.cpp +++ b/async/autotests/asynctest.cpp @@ -40,28 +40,26 @@ public: private Q_SLOTS: void testSyncPromises(); void testAsyncPromises(); + void testSyncEach(); }; void AsyncTest::testSyncPromises() { auto baseJob = Async::start( - []() -> Async::Future { - auto f = Async::Future(42); + [](Async::Future &f) { + f.setValue(42); f.setFinished(); - return f; }) .then( - [](int v) -> Async::Future { - auto f = Async::Future("Result is " + QString::number(v)); + [](int v, Async::Future &f) { + f.setValue("Result is " + QString::number(v)); f.setFinished(); - return f; }); auto job = baseJob.then( - [](const QString &v) -> Async::Future { - auto f = Async::Future(v.toUpper()); + [](const QString &v, Async::Future &f) { + f.setValue(v.toUpper()); f.setFinished(); - return f; }); job.exec(); @@ -73,8 +71,7 @@ void AsyncTest::testSyncPromises() void AsyncTest::testAsyncPromises() { auto job = Async::start( - []() -> Async::Future { - Async::Future future(-1); + [](Async::Future &future) { QTimer *timer = new QTimer(); QObject::connect(timer, &QTimer::timeout, [&]() { @@ -85,7 +82,6 @@ void AsyncTest::testAsyncPromises() timer, &QObject::deleteLater); timer->setSingleShot(true); timer->start(200); - return future; }); job.exec(); @@ -93,6 +89,22 @@ void AsyncTest::testAsyncPromises() QCOMPARE(future.value(), 42); } +void AsyncTest::testSyncEach() +{ + /* + auto job = Async::start>( + []() -> Async::Future> { + Async::Future> future(QList{ 1, 2, 3, 4 }); + future.setFinished(); + return future; + }) + .each, int>( + [](const int &v, Async::Future> &future) { + setFinished(); + }); + */ +} + QTEST_MAIN(AsyncTest); diff --git a/async/src/async.h b/async/src/async.h index 239927d..182e57c 100644 --- a/async/src/async.h +++ b/async/src/async.h @@ -39,13 +39,20 @@ class JobBase; template class Job; -template -Job start(F func); +template +using ThenTask = typename detail::identity&)>>::type; +template +using EachTask = typename detail::identity&)>>::type; +template +using ReduceTask = typename detail::identity&)>>::type; + +template +Job start(ThenTask func); namespace Private { template - Async::Future* doExec(Job *job, const In & ... args); + void doExec(Job *job, Async::Future &out, const In & ... args); } class JobBase @@ -56,7 +63,8 @@ class JobBase protected: enum JobType { Then, - Each + Each, + Reduce }; public: @@ -75,8 +83,8 @@ class Job : public JobBase template friend class Job; - template - friend Job start(F_ func); + template + friend Job start(Async::ThenTask func); typedef Out OutType; typedef typename std::tuple_element<0, std::tuple>::type InType; @@ -87,16 +95,28 @@ public: delete reinterpret_cast*>(mResult); } - template - Job then(F func) + template + Job then(ThenTask func) { return Job::create(func, JobBase::Then, this); } - template - Job each(F func) + template + Job each(EachTask func) { - return Job::create(func, JobBase::Each, this); + static_assert(detail::isIterable::value, + "The 'Each' task can only be connected to a job that returns a list or array."); + static_assert(detail::isIterable::value, + "The result type of 'Each' task must be a list or an array."); + return Job::create(func, JobBase::Each, this); + } + + template + Job reduce(ReduceTask func) + { + static_assert(Async::detail::isIterable::value, + "The result type of 'Reduce' task must be a list or an array."); + return Job::create(func, JobBase::Reduce, this); } Async::Future result() const @@ -116,7 +136,7 @@ private: static Job create(F func, JobBase::JobType jobType, JobBase *parent = nullptr); public: - std::function(In ...)> mFunc; + std::function&)> mFunc; }; @@ -126,16 +146,16 @@ public: // ********** Out of line definitions **************** -template -Async::Job Async::start(F func) +template +Async::Job Async::start(ThenTask func) { return Job::create(func, JobBase::Then); } template -Async::Future* Async::Private::doExec(Job *job, const In & ... args) +void Async::Private::doExec(Job *job, Async::Future &out, const In & ... args) { - return new Async::Future(job->mFunc(args ...)); + job->mFunc(args ..., out); }; template @@ -148,10 +168,10 @@ void Async::Job::exec() assert(in->isFinished()); } - Job *job = dynamic_cast*>(this); - Async::Future *out = Private::doExec(this, in ? in->value() : In() ...); + auto out = new Async::Future(); + Private::doExec(this, *out, in ? in->value() : In() ...); out->waitForFinished(); - job->mResult = reinterpret_cast(out); + mResult = reinterpret_cast(out); } template diff --git a/async/src/async_impl.h b/async/src/async_impl.h index 46bc25d..7b5c140 100644 --- a/async/src/async_impl.h +++ b/async/src/async_impl.h @@ -26,7 +26,26 @@ namespace Async { +namespace detail { + +template +struct identity +{ + typedef T type; +}; + +template +struct isIterable { + enum { value = 0 }; +}; + +template +struct isIterable::type> { + enum { value = 1 }; +}; + +} // namespace Detail } // namespace Async -#endif // ASYNC_IMPL_H \ No newline at end of file +#endif // ASYNC_IMPL_H -- cgit v1.2.3