X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/d1f1e22acb2e2342b535c3847e804b4a5fee3167..c03f25d8392641f56b58640f2c5ddd3fc31b8961:/include/xbt/future.hpp?ds=inline diff --git a/include/xbt/future.hpp b/include/xbt/future.hpp index d5a31a55ce..7fdfb0b807 100644 --- a/include/xbt/future.hpp +++ b/include/xbt/future.hpp @@ -7,16 +7,173 @@ #ifndef XBT_FUTURE_HPP #define XBT_FUTURE_HPP -#include +#include + #include #include namespace simgrid { namespace xbt { +/** A value or an exception + * + * The API is similar to the one of future and promise. + **/ +template +class Result { + enum class ResultStatus { + invalid, + value, + exception, + }; +public: + Result() {} + ~Result() { this->reset(); } + + // Copy (if T is copyable) and move: + Result(Result const& that) + { + (*this) = that; + } + Result& operator=(Result const& that) + { + this->reset(); + switch (that.status_) { + case ResultStatus::invalid: + break; + case ResultStatus::valid: + new (&value_) T(that.value); + break; + case ResultStatus::exception: + new (&exception_) T(that.exception); + break; + } + return *this; + } + Result(Result&& that) + { + *this = std::move(that); + } + Result& operator=(Result&& that) + { + this->reset(); + switch (that.status_) { + case ResultStatus::invalid: + break; + case ResultStatus::valid: + new (&value_) T(std::move(that.value)); + that.value.~T(); + break; + case ResultStatus::exception: + new (&exception_) T(std::move(that.exception)); + that.exception.~exception_ptr(); + break; + } + that.status_ = ResultStatus::invalid; + return *this; + } + + bool is_valid() + { + return status_ != ResultStatus::invalid; + } + void reset() + { + switch(status_) { + case ResultStatus::invalid: + break; + case ResultStatus::value: + value_.~T(); + break; + case ResultStatus::exception: + exception_.~exception_ptr(); + break; + } + status_ = ResultStatus::invalid; + } + void set_exception(std::exception_ptr e) + { + this->reset(); + new (&exception_) std::exception_ptr(std::move(e)); + status_ = ResultStatus::exception; + } + void set_value(T&& value) + { + this->reset(); + new (&value_) T(std::move(value)); + status_ = ResultStatus::value; + } + void set_value(T const& value) + { + this->reset(); + new (&value_) T(value); + status_ = ResultStatus::value; + } + + /** Extract the value from the future + * + * After this the value is invalid. + **/ + T get() + { + switch(status_) { + case ResultStatus::invalid: + throw std::logic_error("Invalid result"); + case ResultStatus::value: { + T value = std::move(value_); + value_.~T(); + status_ = ResultStatus::invalid; + return std::move(value); + } + case ResultStatus::exception: { + std::exception_ptr exception = std::move(exception_); + exception_.~exception_ptr(); + status_ = ResultStatus::invalid; + std::rethrow_exception(std::move(exception)); + break; + } + } + } +private: + ResultStatus status_ = ResultStatus::invalid; + union { + T value_; + std::exception_ptr exception_; + }; +}; + +template<> +class Result : public Result +{ +public: + void set_value() + { + Result::set_value(nullptr); + } + void get() + { + Result::get(); + } +}; + +template +class Result : public Result> +{ +public: + void set_value(T& value) + { + Result>::set_value(std::ref(value)); + } + T& get() + { + return Result>::get(); + } +}; + /** Fulfill a promise by executing a given code */ template -void fulfillPromise(std::promise& promise, F code) +auto fulfillPromise(R& promise, F&& code) +-> decltype(promise.set_value(code())) { try { promise.set_value(code()); @@ -31,8 +188,9 @@ void fulfillPromise(std::promise& promise, F code) * This is a special version for `std::promise` because the default * version does not compile in this case. */ -template -void fulfillPromise(std::promise& promise, F code) +template +auto fulfillPromise(P& promise, F&& code) +-> decltype(promise.set_value()) { try { (code)();