summaryrefslogtreecommitdiffstats
path: root/async
diff options
context:
space:
mode:
Diffstat (limited to 'async')
-rw-r--r--async/autotests/asynctest.cpp36
-rw-r--r--async/src/async.h58
-rw-r--r--async/src/async_impl.h21
3 files changed, 83 insertions, 32 deletions
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:
40private Q_SLOTS: 40private Q_SLOTS:
41 void testSyncPromises(); 41 void testSyncPromises();
42 void testAsyncPromises(); 42 void testAsyncPromises();
43 void testSyncEach();
43}; 44};
44 45
45void AsyncTest::testSyncPromises() 46void AsyncTest::testSyncPromises()
46{ 47{
47 auto baseJob = Async::start<int>( 48 auto baseJob = Async::start<int>(
48 []() -> Async::Future<int> { 49 [](Async::Future<int> &f) {
49 auto f = Async::Future<int>(42); 50 f.setValue(42);
50 f.setFinished(); 51 f.setFinished();
51 return f;
52 }) 52 })
53 .then<QString, int>( 53 .then<QString, int>(
54 [](int v) -> Async::Future<QString> { 54 [](int v, Async::Future<QString> &f) {
55 auto f = Async::Future<QString>("Result is " + QString::number(v)); 55 f.setValue("Result is " + QString::number(v));
56 f.setFinished(); 56 f.setFinished();
57 return f;
58 }); 57 });
59 58
60 auto job = baseJob.then<QString, QString>( 59 auto job = baseJob.then<QString, QString>(
61 [](const QString &v) -> Async::Future<QString> { 60 [](const QString &v, Async::Future<QString> &f) {
62 auto f = Async::Future<QString>(v.toUpper()); 61 f.setValue(v.toUpper());
63 f.setFinished(); 62 f.setFinished();
64 return f;
65 }); 63 });
66 64
67 job.exec(); 65 job.exec();
@@ -73,8 +71,7 @@ void AsyncTest::testSyncPromises()
73void AsyncTest::testAsyncPromises() 71void AsyncTest::testAsyncPromises()
74{ 72{
75 auto job = Async::start<int>( 73 auto job = Async::start<int>(
76 []() -> Async::Future<int> { 74 [](Async::Future<int> &future) {
77 Async::Future<int> future(-1);
78 QTimer *timer = new QTimer(); 75 QTimer *timer = new QTimer();
79 QObject::connect(timer, &QTimer::timeout, 76 QObject::connect(timer, &QTimer::timeout,
80 [&]() { 77 [&]() {
@@ -85,7 +82,6 @@ void AsyncTest::testAsyncPromises()
85 timer, &QObject::deleteLater); 82 timer, &QObject::deleteLater);
86 timer->setSingleShot(true); 83 timer->setSingleShot(true);
87 timer->start(200); 84 timer->start(200);
88 return future;
89 }); 85 });
90 86
91 job.exec(); 87 job.exec();
@@ -93,6 +89,22 @@ void AsyncTest::testAsyncPromises()
93 QCOMPARE(future.value(), 42); 89 QCOMPARE(future.value(), 42);
94} 90}
95 91
92void AsyncTest::testSyncEach()
93{
94 /*
95 auto job = Async::start<QList<int>>(
96 []() -> Async::Future<QList<int>> {
97 Async::Future<QList<int>> future(QList<int>{ 1, 2, 3, 4 });
98 future.setFinished();
99 return future;
100 })
101 .each<QList<int>, int>(
102 [](const int &v, Async::Future<QList<int>> &future) {
103 setFinished();
104 });
105 */
106}
107
96 108
97QTEST_MAIN(AsyncTest); 109QTEST_MAIN(AsyncTest);
98 110
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;
39template<typename Out, typename ... In> 39template<typename Out, typename ... In>
40class Job; 40class Job;
41 41
42template<typename Out, typename ... In, typename F> 42template<typename Out, typename ... In>
43Job<Out, In ...> start(F func); 43using ThenTask = typename detail::identity<std::function<void(In ..., Async::Future<Out>&)>>::type;
44template<typename Out, typename In>
45using EachTask = typename detail::identity<std::function<void(In, Async::Future<Out>&)>>::type;
46template<typename Out, typename In>
47using ReduceTask = typename detail::identity<std::function<void(In, Async::Future<Out>&)>>::type;
48
49template<typename Out, typename ... In>
50Job<Out, In ...> start(ThenTask<Out, In ...> func);
44 51
45namespace Private 52namespace Private
46{ 53{
47 template<typename Out, typename ... In> 54 template<typename Out, typename ... In>
48 Async::Future<Out>* doExec(Job<Out, In ...> *job, const In & ... args); 55 void doExec(Job<Out, In ...> *job, Async::Future<Out> &out, const In & ... args);
49} 56}
50 57
51class JobBase 58class JobBase
@@ -56,7 +63,8 @@ class JobBase
56protected: 63protected:
57 enum JobType { 64 enum JobType {
58 Then, 65 Then,
59 Each 66 Each,
67 Reduce
60 }; 68 };
61 69
62public: 70public:
@@ -75,8 +83,8 @@ class Job : public JobBase
75 template<typename Out_, typename ... In_> 83 template<typename Out_, typename ... In_>
76 friend class Job; 84 friend class Job;
77 85
78 template<typename Out_, typename ... In_, typename F_> 86 template<typename Out_, typename ... In_>
79 friend Job<Out_, In_ ...> start(F_ func); 87 friend Job<Out_, In_ ...> start(Async::ThenTask<Out_, In_ ...> func);
80 88
81 typedef Out OutType; 89 typedef Out OutType;
82 typedef typename std::tuple_element<0, std::tuple<In ..., void>>::type InType; 90 typedef typename std::tuple_element<0, std::tuple<In ..., void>>::type InType;
@@ -87,16 +95,28 @@ public:
87 delete reinterpret_cast<Async::Future<Out>*>(mResult); 95 delete reinterpret_cast<Async::Future<Out>*>(mResult);
88 } 96 }
89 97
90 template<typename Out_, typename ... In_, typename F> 98 template<typename Out_, typename ... In_>
91 Job<Out_, In_ ...> then(F func) 99 Job<Out_, In_ ...> then(ThenTask<Out_, In_ ...> func)
92 { 100 {
93 return Job<Out_, In_ ...>::create(func, JobBase::Then, this); 101 return Job<Out_, In_ ...>::create(func, JobBase::Then, this);
94 } 102 }
95 103
96 template<typename Out_, typename ... In_, typename F> 104 template<typename Out_, typename In_>
97 Job<Out_, In_ ...> each(F func) 105 Job<Out_, In_> each(EachTask<Out_, In_> func)
98 { 106 {
99 return Job<Out_, In_ ...>::create(func, JobBase::Each, this); 107 static_assert(detail::isIterable<OutType>::value,
108 "The 'Each' task can only be connected to a job that returns a list or array.");
109 static_assert(detail::isIterable<Out_>::value,
110 "The result type of 'Each' task must be a list or an array.");
111 return Job<Out_, In_>::create(func, JobBase::Each, this);
112 }
113
114 template<typename Out_, typename In_>
115 Job<Out_, In_> reduce(ReduceTask<Out_, In_> func)
116 {
117 static_assert(Async::detail::isIterable<OutType>::value,
118 "The result type of 'Reduce' task must be a list or an array.");
119 return Job<Out_, In_>::create(func, JobBase::Reduce, this);
100 } 120 }
101 121
102 Async::Future<Out> result() const 122 Async::Future<Out> result() const
@@ -116,7 +136,7 @@ private:
116 static Job<Out, In ... > create(F func, JobBase::JobType jobType, JobBase *parent = nullptr); 136 static Job<Out, In ... > create(F func, JobBase::JobType jobType, JobBase *parent = nullptr);
117 137
118public: 138public:
119 std::function<Async::Future<Out>(In ...)> mFunc; 139 std::function<void(In ..., Async::Future<Out>&)> mFunc;
120}; 140};
121 141
122 142
@@ -126,16 +146,16 @@ public:
126 146
127// ********** Out of line definitions **************** 147// ********** Out of line definitions ****************
128 148
129template<typename Out, typename ... In, typename F> 149template<typename Out, typename ... In>
130Async::Job<Out, In ...> Async::start(F func) 150Async::Job<Out, In ...> Async::start(ThenTask<Out, In ...> func)
131{ 151{
132 return Job<Out, In ...>::create(func, JobBase::Then); 152 return Job<Out, In ...>::create(func, JobBase::Then);
133} 153}
134 154
135template<typename Out, typename ... In> 155template<typename Out, typename ... In>
136Async::Future<Out>* Async::Private::doExec(Job<Out, In ...> *job, const In & ... args) 156void Async::Private::doExec(Job<Out, In ...> *job, Async::Future<Out> &out, const In & ... args)
137{ 157{
138 return new Async::Future<Out>(job->mFunc(args ...)); 158 job->mFunc(args ..., out);
139}; 159};
140 160
141template<typename Out, typename ... In> 161template<typename Out, typename ... In>
@@ -148,10 +168,10 @@ void Async::Job<Out, In ...>::exec()
148 assert(in->isFinished()); 168 assert(in->isFinished());
149 } 169 }
150 170
151 Job<Out, In ...> *job = dynamic_cast<Job<Out, In ...>*>(this); 171 auto out = new Async::Future<Out>();
152 Async::Future<Out> *out = Private::doExec<Out, In ...>(this, in ? in->value() : In() ...); 172 Private::doExec<Out, In ...>(this, *out, in ? in->value() : In() ...);
153 out->waitForFinished(); 173 out->waitForFinished();
154 job->mResult = reinterpret_cast<void*>(out); 174 mResult = reinterpret_cast<void*>(out);
155} 175}
156 176
157template<typename Out, typename ... In> 177template<typename Out, typename ... In>
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 @@
26 26
27namespace Async { 27namespace Async {
28 28
29namespace detail {
30
31template<typename T>
32struct identity
33{
34 typedef T type;
35};
36
37template<typename T, typename Enable = void>
38struct isIterable {
39 enum { value = 0 };
40};
41
42template<typename T>
43struct isIterable<T, typename std::conditional<false, typename T::iterator, void>::type> {
44 enum { value = 1 };
45};
46
47} // namespace Detail
29 48
30} // namespace Async 49} // namespace Async
31 50
32#endif // ASYNC_IMPL_H \ No newline at end of file 51#endif // ASYNC_IMPL_H