X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/167580ed173f1267354e8e1962a77149e760dcc2..c3afdfa7a603897d1fbca56e7d1705983038405e:/include/simgrid/kernel/future.hpp diff --git a/include/simgrid/kernel/future.hpp b/include/simgrid/kernel/future.hpp index 9b6a5fc88b..cedfd39c96 100644 --- a/include/simgrid/kernel/future.hpp +++ b/include/simgrid/kernel/future.hpp @@ -7,6 +7,9 @@ #ifndef SIMGRID_KERNEL_FUTURE_HPP #define SIMGRID_KERNEL_FUTURE_HPP +#include +#include + #include #include @@ -35,6 +38,11 @@ enum class FutureStatus { done, }; +template +struct is_future : public std::integral_constant {}; +template +struct is_future> : public std::integral_constant {}; + /** Bases stuff for all @ref simgrid::kernel::FutureState */ class FutureStateBase { public: @@ -195,6 +203,24 @@ public: } }; +template +void bindPromise(Promise promise, Future future) +{ + struct PromiseBinder { + public: + PromiseBinder(Promise promise) : promise_(std::move(promise)) {} + void operator()(Future future) + { + simgrid::xbt::setPromise(promise_, future); + } + private: + Promise promise_; + }; + future.then_(PromiseBinder(std::move(promise))); +} + +template Future unwrapFuture(Future> future); + /** Result of some (probably) asynchronous operation in the SimGrid kernel * * @ref simgrid::simix::Future and @ref simgrid::simix::Future provide an @@ -289,27 +315,78 @@ public: return state_ != nullptr && state_->is_ready(); } + /** Attach a continuation to this future + * + * This is like .then() but avoid the creation of a new future. + */ + template + void then_(F continuation) + { + if (state_ == nullptr) + throw std::future_error(std::future_errc::no_state); + // Give shared-ownership to the continuation: + auto state = std::move(state_); + state->set_continuation(simgrid::xbt::makeTask( + std::move(continuation), state)); + } + + /** Attach a continuation to this future + * + * This version never does future unwrapping. + */ + template + auto thenNoUnwrap(F continuation) + -> Future + { + typedef decltype(continuation(std::move(*this))) R; + if (state_ == nullptr) + throw std::future_error(std::future_errc::no_state); + auto state = std::move(state_); + // Create a new future... + Promise promise; + Future future = promise.get_future(); + // ...and when the current future is ready... + state->set_continuation(simgrid::xbt::makeTask( + [](Promise promise, std::shared_ptr> state, F continuation) { + // ...set the new future value by running the continuation. + Future future(std::move(state)); + simgrid::xbt::fulfillPromise(promise,[&]{ + return continuation(std::move(future)); + }); + }, + std::move(promise), state, std::move(continuation))); + return std::move(future); + } + /** Attach a continuation to this future * * The future must be valid in order to make this call. * The continuation is executed when the future becomes ready. * The future becomes invalid after this call. * - * We don't support future chaining for now (`.then().then()`). - * * @param continuation This function is called with a ready future * the future is ready * @exception std::future_error no state is associated with the future */ template - void then(F continuation) + auto then(F continuation) + -> typename std::enable_if< + !is_future::value, + Future + >::type { - if (state_ == nullptr) - throw std::future_error(std::future_errc::no_state); - // Give shared-ownership to the continuation: - auto state = std::move(state_); - state->set_continuation(simgrid::xbt::makeTask( - std::move(continuation), state)); + return this->thenNoUnwrap(std::move(continuation)); + } + + /** Attach a continuation to this future (future chaining) */ + template + auto then(F continuation) + -> typename std::enable_if< + is_future::value, + decltype(continuation(std::move(*this))) + >::type + { + return unwrapFuture(this->thenNoUnwap(std::move(continuation))); } /** Get the value from the future @@ -337,6 +414,15 @@ private: std::shared_ptr> state_; }; +template +Future unwrapFuture(Future> future) +{ + Promise promise; + Future result = promise.get_future(); + bindPromise(std::move(promise), std::move(future)); + return std::move(result); +} + /** Producer side of a @simgrid::kernel::Future * * A @ref Promise is connected to some `Future` and can be used to @@ -376,10 +462,10 @@ public: Promise(std::shared_ptr> state) : state_(std::move(state)) {} // Move type - Promise(Promise&) = delete; - Promise& operator=(Promise&) = delete; + Promise(Promise const&) = delete; + Promise& operator=(Promise const&) = delete; Promise(Promise&& that) : - state_(std::move(that.state_)), future_get_(that.future_set) + state_(std::move(that.state_)), future_get_(that.future_get_) { that.future_get_ = false; } @@ -437,8 +523,8 @@ public: } // Move type - Promise(Promise&) = delete; - Promise& operator=(Promise&) = delete; + Promise(Promise const&) = delete; + Promise& operator=(Promise const&) = delete; Promise(Promise&& that) : state_(std::move(that.state_)), future_get_(that.future_get_) {