future: add then_wrapped()

Unlike future::then(), which unwraps the value, then_wrapped() keeps it
wrapped in a future<>, so if it is exceptional, it can still be accessed.

This is similar to the proposed std::future::then(), so we should later
rename it to match (and rename the existing future::then() to future::next().
This commit is contained in:
Avi Kivity
2014-10-30 13:55:31 +02:00
parent fa7ea4f86e
commit c4bc67414e

View File

@@ -257,6 +257,7 @@ template <typename... T> struct is_future : std::false_type {};
template <typename... T> struct is_future<future<T...>> : std::true_type {};
struct ready_future_marker {};
struct ready_future_from_tuple_marker {};
struct exception_future_marker {};
template <typename... T>
@@ -273,6 +274,10 @@ private:
future(ready_future_marker, A&&... a) : _promise(nullptr) {
_local_state.set(std::forward<A>(a)...);
}
template <typename... A>
future(ready_future_from_tuple_marker, std::tuple<A...>&& data) : _promise(nullptr) {
_local_state.set(std::move(data));
}
future(exception_future_marker, std::exception_ptr ex) noexcept : _promise(nullptr) {
_local_state.set_exception(std::move(ex));
}
@@ -386,6 +391,34 @@ public:
return next_fut;
}
template <typename Func>
std::result_of_t<Func(future<T...>)>
then_wrapped(Func&& func) && noexcept {
using P = typename std::result_of_t<Func(future<T...>)>::promise_type;
if (state()->available()) {
try {
return func(std::move(*this));
} catch (...) {
P pr;
pr.set_exception(std::current_exception());
return pr.get_future();
}
}
P pr;
auto next_fut = pr.get_future();
_promise->schedule([func = std::forward<Func>(func), pr = std::move(pr)] (auto& state) mutable {
try {
auto next_fut = func(future(ready_future_from_tuple_marker(), state.get()));
next_fut.forward_to(std::move(pr));
} catch (...) {
pr.set_exception(std::current_exception());
}
});
_promise->_future = nullptr;
_promise = nullptr;
return next_fut;
}
template <typename Func>
future<> rescue(Func&& func) noexcept {
if (state()->available()) {