Merge branch 'tgrabiec/futurize' of github.com:cloudius-systems/seastar-dev

Unify future callback specialization for callback return values, from
Tomasz.
This commit is contained in:
Avi Kivity
2015-03-06 12:40:17 +02:00
3 changed files with 105 additions and 99 deletions

View File

@@ -248,29 +248,4 @@ future<> now() {
return make_ready_future<>();
}
// Converts a type to a future type, if it isn't already.
//
// Result in member type 'type'.
template <typename T>
struct futurize;
template <typename T>
struct futurize {
using type = future<T>;
};
template <>
struct futurize<void> {
using type = future<>;
};
template <typename... Args>
struct futurize<future<Args...>> {
using type = future<Args...>;
};
// Converts a type to a future type, if it isn't already.
template <typename T>
using futurize_t = typename futurize<T>::type;
#endif /* CORE_FUTURE_UTIL_HH_ */

View File

@@ -353,6 +353,52 @@ struct exception_future_marker {};
extern __thread size_t future_avail_count;
// Converts a type to a future type, if it isn't already.
//
// Result in member type 'type'.
template <typename T>
struct futurize;
template <typename T>
struct futurize {
using type = future<T>;
using promise_type = promise<T>;
template<typename Func, typename... FuncArgs>
static inline type apply(Func&& func, std::tuple<FuncArgs...>&& args);
template<typename Func, typename... FuncArgs>
static inline type apply(Func&& func, FuncArgs&&... args);
};
template <>
struct futurize<void> {
using type = future<>;
using promise_type = promise<>;
template<typename Func, typename... FuncArgs>
static inline type apply(Func&& func, std::tuple<FuncArgs...>&& args);
template<typename Func, typename... FuncArgs>
static inline type apply(Func&& func, FuncArgs&&... args);
};
template <typename... Args>
struct futurize<future<Args...>> {
using type = future<Args...>;
using promise_type = promise<Args...>;
template<typename Func, typename... FuncArgs>
static inline type apply(Func&& func, std::tuple<FuncArgs...>&& args);
template<typename Func, typename... FuncArgs>
static inline type apply(Func&& func, FuncArgs&&... args);
};
// Converts a type to a future type, if it isn't already.
template <typename T>
using futurize_t = typename futurize<T>::type;
template <typename... T>
class future {
promise<T...>* _promise;
@@ -436,27 +482,23 @@ public:
return state()->failed();
}
template <typename Func, typename Enable>
void then(Func, Enable) noexcept;
template <typename Func>
future<> then(Func&& func,
std::enable_if_t<std::is_same<std::result_of_t<Func(T&&...)>, void>::value, void*> = nullptr) noexcept {
futurize_t<std::result_of_t<Func(T&&...)>> then(Func&& func) noexcept {
using futurator = futurize<std::result_of_t<Func(T&&...)>>;
if (state()->available() && (++future_avail_count % 256)) {
try {
apply(std::move(func), std::move(state()->get()));
return make_ready_future<>();
return futurator::apply(std::forward<Func>(func), std::move(state()->get()));
} catch (...) {
return make_exception_future(std::current_exception());
typename futurator::promise_type p;
p.set_exception(std::current_exception());
return p.get_future();
}
}
promise<> pr;
typename futurator::promise_type pr;
auto fut = pr.get_future();
schedule([pr = std::move(pr), func = std::forward<Func>(func)] (auto& state) mutable {
try {
apply(std::move(func), state.get());
pr.set_value();
futurator::apply(std::forward<Func>(func), state.get()).forward_to(std::move(pr));
} catch (...) {
pr.set_exception(std::current_exception());
}
@@ -475,41 +517,13 @@ public:
}
template <typename Func>
std::result_of_t<Func(T&&...)>
then(Func&& func,
std::enable_if_t<is_future<std::result_of_t<Func(T&&...)>>::value, void*> = nullptr) noexcept {
using P = typename std::result_of_t<Func(T&&...)>::promise_type;
if (state()->available() && (++future_avail_count % 256)) {
try {
return apply(std::move(func), std::move(state()->get()));
} catch (...) {
P pr;
pr.set_exception(std::current_exception());
return pr.get_future();
}
}
P pr;
auto next_fut = pr.get_future();
schedule([func = std::forward<Func>(func), pr = std::move(pr)] (auto& state) mutable {
try {
auto result = state.get();
auto next_fut = apply(std::move(func), std::move(result));
next_fut.forward_to(std::move(pr));
} catch (...) {
pr.set_exception(std::current_exception());
}
});
return next_fut;
}
template <typename Func>
std::result_of_t<Func(future<T...>)>
then_wrapped(Func&& func,
std::enable_if_t<is_future<std::result_of_t<Func(future<T...>)>>::value, void*> = nullptr) && noexcept {
using P = typename std::result_of_t<Func(future<T...>)>::promise_type;
futurize_t<std::result_of_t<Func(future<T...>)>>
then_wrapped(Func&& func) && noexcept {
using futurator = futurize<std::result_of_t<Func(future<T...>)>>;
using P = typename futurator::promise_type;
if (state()->available()) {
try {
return func(std::move(*this));
return futurator::apply(std::forward<Func>(func), std::move(*this));
} catch (...) {
P pr;
pr.set_exception(std::current_exception());
@@ -520,35 +534,8 @@ public:
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(std::move(state)));
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<>
then_wrapped(Func&& func,
std::enable_if_t<std::is_same<std::result_of_t<Func(future<T...>)>, void>::value, void*> = nullptr) && noexcept {
if (state()->available()) {
try {
func(std::move(*this));
return make_ready_future<>();
} catch (...) {
return make_exception_future(std::current_exception());
}
}
promise<> pr;
auto next_fut = pr.get_future();
_promise->schedule([func = std::forward<Func>(func), pr = std::move(pr)] (auto& state) mutable {
try {
func(future(std::move(state)));
pr.set_value();
futurator::apply(std::forward<Func>(func), future(std::move(state)))
.forward_to(std::move(pr));
} catch (...) {
pr.set_exception(std::current_exception());
}
@@ -693,4 +680,40 @@ future<T...> make_exception_future(Exception&& ex) noexcept {
return make_exception_future<T...>(std::make_exception_ptr(std::forward<Exception>(ex)));
}
template<typename T>
template<typename Func, typename... FuncArgs>
typename futurize<T>::type futurize<T>::apply(Func&& func, std::tuple<FuncArgs...>&& args) {
return make_ready_future<T>(::apply(std::forward<Func>(func), std::move(args)));
}
template<typename T>
template<typename Func, typename... FuncArgs>
typename futurize<T>::type futurize<T>::apply(Func&& func, FuncArgs&&... args) {
return make_ready_future<T>(func(std::forward<FuncArgs>(args)...));
}
template<typename Func, typename... FuncArgs>
typename futurize<void>::type futurize<void>::apply(Func&& func, std::tuple<FuncArgs...>&& args) {
::apply(std::forward<Func>(func), std::move(args));
return make_ready_future<>();
}
template<typename Func, typename... FuncArgs>
typename futurize<void>::type futurize<void>::apply(Func&& func, FuncArgs&&... args) {
func(std::forward<FuncArgs>(args)...);
return make_ready_future<>();
}
template<typename... Args>
template<typename Func, typename... FuncArgs>
typename futurize<future<Args...>>::type futurize<future<Args...>>::apply(Func&& func, std::tuple<FuncArgs...>&& args) {
return ::apply(std::forward<Func>(func), std::move(args));
}
template<typename... Args>
template<typename Func, typename... FuncArgs>
typename futurize<future<Args...>>::type futurize<future<Args...>>::apply(Func&& func, FuncArgs&&... args) {
return func(std::forward<FuncArgs>(args)...);
}
#endif /* FUTURE_HH_ */

View File

@@ -232,3 +232,11 @@ SEASTAR_TEST_CASE(test_broken_semaphore) {
sem->broken(oops());
return ret;
}
SEASTAR_TEST_CASE(test_bare_value_can_be_returned_from_callback) {
return now().then([] {
return 3;
}).then([] (int x) {
BOOST_REQUIRE(x == 3);
});
}