From 6b6e2a3ecc1e8f54b0862d66929ed6ace21892e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Thu, 11 Dec 2014 18:24:24 +0100 Subject: Async: move some common code from executors to shared base class --- async/src/async.cpp | 2 +- async/src/async.h | 136 +++++++++++++++++++++++++++++----------------------- 2 files changed, 78 insertions(+), 60 deletions(-) (limited to 'async/src') diff --git a/async/src/async.cpp b/async/src/async.cpp index c4a88fd..16da384 100644 --- a/async/src/async.cpp +++ b/async/src/async.cpp @@ -28,7 +28,7 @@ using namespace Async; -JobBase::JobBase(Executor *executor) +JobBase::JobBase(ExecutorBase *executor) : mExecutor(executor) { } diff --git a/async/src/async.h b/async/src/async.h index a976fa2..52d0570 100644 --- a/async/src/async.h +++ b/async/src/async.h @@ -28,6 +28,7 @@ #include #include #include +#include #include "future.h" #include "async_impl.h" @@ -35,6 +36,9 @@ namespace Async { +template +class Executor; + class JobBase; template @@ -50,17 +54,19 @@ using ReduceTask = typename detail::identity Job start(ThenTask func); -class Executor +template +struct PreviousOut { + using type = typename std::tuple_element<0, std::tuple>::type; +}; + + +class ExecutorBase { + template + friend class Executor; public: - Executor(Executor *parent) - : mPrev(parent) - , mResult(0) - { - } - - virtual ~Executor() + virtual ~ExecutorBase() { delete mResult; } @@ -72,113 +78,125 @@ public: return mResult; } - Executor *mPrev; +protected: + ExecutorBase(ExecutorBase *parent) + : mPrev(parent) + , mResult(0) + { + } + + ExecutorBase *mPrev; FutureBase *mResult; }; -template -class ThenExecutor: public Executor +template +class Executor : public ExecutorBase { - -public: - ThenExecutor(ThenTask then, Executor *parent = nullptr) - : Executor(parent) - , mFunc(then) +protected: + Executor(ExecutorBase *parent) + : ExecutorBase(parent) { } - void exec() + Async::Future* chainup() { - typedef typename std::tuple_element<0, std::tuple>::type PrevOut; - - Async::Future *in = 0; if (mPrev) { mPrev->exec(); - in = static_cast*>(mPrev->result()); - assert(in->isFinished()); + auto future = static_cast*>(mPrev->result()); + assert(future->isFinished()); + return future; + } else { + return 0; } + } + + std::function &)> mFunc; +}; + +template +class ThenExecutor: public Executor::type, Out, In ...> +{ +public: + ThenExecutor(ThenTask then, ExecutorBase *parent = nullptr) + : Executor::type, Out, In ...>(parent) + { + this->mFunc = then; + } + + void exec() + { + auto in = this->chainup(); + (void)in; // supress 'unused variable' warning when In is void auto out = new Async::Future(); - mFunc(in ? in->value() : In() ..., *out); + this->mFunc(in ? in->value() : In() ..., *out); out->waitForFinished(); - mResult = out; + this->mResult = out; } - -private: - std::function&)> mFunc; }; template -class EachExecutor : public Executor +class EachExecutor : public Executor { public: - EachExecutor(EachTask each, Executor *parent = nullptr) - : Executor(parent) - , mFunc(each) + EachExecutor(EachTask each, ExecutorBase *parent) + : Executor(parent) { + this->mFunc = each; } void exec() { - assert(mPrev); - mPrev->exec(); - Async::Future *in = static_cast*>(mPrev->result()); + auto in = this->chainup(); auto *out = new Async::Future(); for (auto arg : in->value()) { Async::Future future; - mFunc(arg, future); + this->mFunc(arg, future); future.waitForFinished(); out->setValue(out->value() + future.value()); } out->setFinished(); - mResult = out; + this->mResult = out; } - -private: - std::function&)> mFunc; }; template -class ReduceExecutor : public Executor +class ReduceExecutor : public Executor { public: - ReduceExecutor(ReduceTask reduce, Executor *parent = nullptr) - : Executor(parent) - , mFunc(reduce) + ReduceExecutor(ReduceTask reduce, ExecutorBase *parent) + : Executor(parent) { + this->mFunc = reduce; } void exec() { - assert(mPrev); - mPrev->exec(); - Async::Future *in = static_cast*>(mPrev->result()); + auto in = this->chainup(); auto out = new Async::Future(); - mFunc(in->value(), *out); + this->mFunc(in->value(), *out); out->waitForFinished(); - mResult = out; + this->mResult = out; } - -private: - std::function &)> mFunc; }; + class JobBase { template friend class Job; public: - JobBase(Executor *executor); + JobBase(ExecutorBase *executor); ~JobBase(); void exec(); protected: - Executor *mExecutor; + ExecutorBase *mExecutor; }; template @@ -194,15 +212,14 @@ public: template Job then(ThenTask func) { - Executor *exec = new ThenExecutor(func, mExecutor); - return Job(exec); + return Job(new ThenExecutor(func, mExecutor)); } template Job each(EachTask func) { static_assert(detail::isIterable::value, - "The 'Each' task can only be connected to a job that returns a list or array."); + "The 'Each' task can only be connected to a job that returns a list or an array."); static_assert(detail::isIterable::value, "The result type of 'Each' task must be a list or an array."); return Job(new EachExecutor(func, mExecutor)); @@ -212,7 +229,9 @@ public: Job reduce(ReduceTask func) { static_assert(Async::detail::isIterable::value, - "The 'Result' task can only be connected to a job that returns a list or array"); + "The 'Result' task can only be connected to a job that returns a list or an array"); + static_assert(std::is_same::value, + "The return type of previous task must be compatible with input type of this task"); return Job(new ReduceExecutor(func, mExecutor)); } @@ -222,7 +241,7 @@ public: } private: - Job(Executor *executor) + Job(ExecutorBase *executor) : JobBase(executor) { } @@ -231,7 +250,6 @@ private: } // namespace Async - // ********** Out of line definitions **************** template -- cgit v1.2.3