From 8f2e8075d660a354a3aabf065998f42802f9cc11 Mon Sep 17 00:00:00 2001 From: Gabriel Corona Date: Mon, 20 Jun 2016 13:59:40 +0200 Subject: [PATCH] Make FutureContinuation reusable in simgrid::xbt::Task --- include/simgrid/kernel/future.hpp | 61 ++++--------------------- include/xbt/functional.hpp | 75 +++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 52 deletions(-) diff --git a/include/simgrid/kernel/future.hpp b/include/simgrid/kernel/future.hpp index c58f46b164..a11c8ec40c 100644 --- a/include/simgrid/kernel/future.hpp +++ b/include/simgrid/kernel/future.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -27,8 +28,6 @@ template class Promise; // Those are implementation details: enum class FutureStatus; template class FutureState; -class FutureContinuation; -template class FutureContinuationImpl; enum class FutureStatus { not_ready, @@ -36,47 +35,6 @@ enum class FutureStatus { done, }; -/** A continuation attached to a future to be executed when it is ready */ -XBT_PUBLIC_CLASS FutureContinuation { -public: - FutureContinuation() {} - - // No copy: - FutureContinuation(FutureContinuation&) = delete; - FutureContinuation& operator=(FutureContinuation&) = delete; - - virtual ~FutureContinuation() {} - virtual void operator()() = 0; -}; - -/** Default implementation of `FutureContinuation` - * - * @param T value type of the future - * @param F type of the wrapped code/callback/continuation - */ -template -class FutureContinuationImpl : public FutureContinuation { -public: - FutureContinuationImpl(std::shared_ptr> ptr, F callback) - : ptr_(std::move(ptr)), callback_(std::move(callback)) {} - ~FutureContinuationImpl() override {} - void operator()() override - { - try { - callback_(Future(ptr_)); - } - // Those exceptions are lost. - // If we want to implement callback chaining, we'll have to catch them and - // foward them to the next future. - catch (...) { - // We could log this. - } - } -private: - std::shared_ptr> ptr_; - F callback_; -}; - /** Bases stuff for all @ref simgrid::kernel::FutureState */ class FutureStateBase { public: @@ -93,7 +51,7 @@ public: this->set_ready(); } - void set_continuation(std::unique_ptr continuation) + void set_continuation(simgrid::xbt::Task continuation) { xbt_assert(!continuation_); switch (status_) { @@ -105,7 +63,7 @@ public: case FutureStatus::ready: // The future is ready, execute the continuation directly. // We might execute it from the event loop instead: - (*continuation)(); + continuation(); break; case FutureStatus::not_ready: // The future is not ready so we mast keep the continuation for @@ -138,7 +96,7 @@ protected: // We need to do this becase the current implementation of the // continuation has a shared_ptr to the FutureState. auto continuation = std::move(continuation_); - (*continuation)(); + continuation(); } } @@ -160,7 +118,7 @@ protected: private: FutureStatus status_ = FutureStatus::not_ready; std::exception_ptr exception_; - std::unique_ptr continuation_; + simgrid::xbt::Task continuation_; }; /** Shared state for future and promises @@ -345,11 +303,10 @@ public: { if (state_ == nullptr) throw std::future_error(std::future_errc::no_state); - std::unique_ptr ptr = - std::unique_ptr( - new FutureContinuationImpl(state_, std::move(continuation))); - state_->set_continuation(std::move(ptr)); - state_ = nullptr; + // Give shared-ownership to the continuation: + auto state = std::move(state_); + state->set_continuation(simgrid::xbt::makeTask( + std::move(continuation), state)); } /** Get the value from the future diff --git a/include/xbt/functional.hpp b/include/xbt/functional.hpp index 537ba8f9dc..1f8abfbb20 100644 --- a/include/xbt/functional.hpp +++ b/include/xbt/functional.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -153,6 +154,80 @@ constexpr auto apply(F&& f, Tuple&& t) >()); } +template class Task; + +/** Type-erased run-once task + * + * * Like std::function but callable only once. + * However, it works with move-only types. + * + * * Like std::packaged_task<> but without the shared state. + */ +template +class Task { +private: + // Type-erasure for the code: + class Base { + public: + virtual ~Base() {} + virtual R operator()(Args...) = 0; + }; + template + class Impl : public Base { + public: + Impl(F&& code) : code_(std::move(code)) {} + Impl(F const& code) : code_(code) {} + ~Impl() override {} + R operator()(Args... args) + { + return code_(std::forward(args)...); + } + private: + F code_; + }; + std::unique_ptr code_; +public: + Task() {} + Task(std::nullptr_t) {} + + template + Task(F&& code) : + code_(new Impl(std::forward(code))) {} + + operator bool() const { return code_ != nullptr; } + bool operator!() const { return code_ == nullptr; } + + template + R operator()(OtherArgs&&... args) + { + std::unique_ptr code = std::move(code_); + return (*code)(std::forward(args)...); + } +}; + +template +auto makeTask(F code, Args... args) +-> Task< decltype(code(std::move(args)...))() > +{ + typedef decltype(code(std::move(args)...)) result_type; + + class Impl { + private: + F code_; + std::tuple args_; + public: + Impl(F code, std::tuple args) : + code_(std::move(code)), + args_(std::move(args)) {} + result_type operator()() + { + return simgrid::xbt::apply(std::move(code_), std::move(args_)); + } + }; + + return Impl(std::move(code), std::make_tuple(std::move(args)...)); +} + } } -- 2.20.1