1 /* Copyright (c) 2015-2017. The SimGrid Team.
2 * All rights reserved. */
4 /* This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
15 #include <type_traits>
22 /** A value or an exception (or nothing)
24 * This is similar to `optional<expected<T>>`` but it with a Future/Promise
27 * Also the name is not so great.
31 enum class ResultStatus {
37 Result() { /* Nothing to do */}
38 ~Result() { this->reset(); }
40 // Copy (if T is copyable) and move:
41 Result(Result const& that)
45 Result& operator=(Result const& that)
48 switch (that.status_) {
49 case ResultStatus::invalid:
51 case ResultStatus::value:
52 new (&value_) T(that.value);
54 case ResultStatus::exception:
55 new (&exception_) T(that.exception);
64 *this = std::move(that);
66 Result& operator=(Result&& that)
69 switch (that.status_) {
70 case ResultStatus::invalid:
72 case ResultStatus::value:
73 new (&value_) T(std::move(that.value));
76 case ResultStatus::exception:
77 new (&exception_) T(std::move(that.exception));
78 that.exception.~exception_ptr();
83 that.status_ = ResultStatus::invalid;
89 return status_ != ResultStatus::invalid;
94 case ResultStatus::invalid:
96 case ResultStatus::value:
99 case ResultStatus::exception:
100 exception_.~exception_ptr();
105 status_ = ResultStatus::invalid;
107 void set_exception(std::exception_ptr e)
110 new (&exception_) std::exception_ptr(std::move(e));
111 status_ = ResultStatus::exception;
113 void set_value(T&& value)
116 new (&value_) T(std::move(value));
117 status_ = ResultStatus::value;
119 void set_value(T const& value)
122 new (&value_) T(value);
123 status_ = ResultStatus::value;
126 /** Extract the value from the future
128 * After this, the value is invalid.
133 case ResultStatus::value: {
134 T value = std::move(value_);
136 status_ = ResultStatus::invalid;
137 return std::move(value);
139 case ResultStatus::exception: {
140 std::exception_ptr exception = std::move(exception_);
141 exception_.~exception_ptr();
142 status_ = ResultStatus::invalid;
143 std::rethrow_exception(std::move(exception));
147 throw std::logic_error("Invalid result");
151 ResultStatus status_ = ResultStatus::invalid;
154 std::exception_ptr exception_;
159 class Result<void> : public Result<std::nullptr_t>
164 Result<std::nullptr_t>::set_value(nullptr);
168 Result<std::nullptr_t>::get();
173 class Result<T&> : public Result<std::reference_wrapper<T>>
176 void set_value(T& value)
178 Result<std::reference_wrapper<T>>::set_value(std::ref(value));
182 return Result<std::reference_wrapper<T>>::get();
186 /** Execute some code and set a promise or result accordingly
191 * promise.set_value(code());
194 * but it takes care of exceptions and works with `void`.
196 * We might need this when working with generic code because
197 * the trivial implementation does not work with `void` (before C++1z).
199 * @param code What we want to do
200 * @param promise Where to want to store the result
202 template<class R, class F>
203 auto fulfillPromise(R& promise, F&& code)
204 -> decltype(promise.set_value(code()))
207 promise.set_value(std::forward<F>(code)());
210 promise.set_exception(std::current_exception());
214 template<class P, class F>
215 auto fulfillPromise(P& promise, F&& code)
216 -> decltype(promise.set_value())
219 std::forward<F>(code)();
223 promise.set_exception(std::current_exception());
227 /** Set a promise/result from a future/result
231 * <pre>promise.set_value(future);</pre>
233 * but it takes care of exceptions and works with `void`.
235 * We might need this when working with generic code because
236 * the trivial implementation does not work with `void` (before C++1z).
238 * @param promise output (a valid future or a result)
239 * @param future input (a ready/waitable future or a valid result)
241 template<class P, class F> inline
242 void setPromise(P& promise, F&& future)
244 fulfillPromise(promise, [&]{ return std::forward<F>(future).get(); });