From f5485c667d1b9649b41e46c30297c932a6184e2a Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Fri, 6 Mar 2015 10:00:47 +0100 Subject: [PATCH 1/6] core: Move futurize<> to future.hh --- core/future-util.hh | 25 ------------------------- core/future.hh | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/core/future-util.hh b/core/future-util.hh index 8b290807a0..70bc666bb8 100644 --- a/core/future-util.hh +++ b/core/future-util.hh @@ -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 -struct futurize; - -template -struct futurize { - using type = future; -}; - -template <> -struct futurize { - using type = future<>; -}; - -template -struct futurize> { - using type = future; -}; - -// Converts a type to a future type, if it isn't already. -template -using futurize_t = typename futurize::type; - #endif /* CORE_FUTURE_UTIL_HH_ */ diff --git a/core/future.hh b/core/future.hh index c459e6e03e..2a9c69022a 100644 --- a/core/future.hh +++ b/core/future.hh @@ -353,6 +353,31 @@ 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 +struct futurize; + +template +struct futurize { + using type = future; +}; + +template <> +struct futurize { + using type = future<>; +}; + +template +struct futurize> { + using type = future; +}; + +// Converts a type to a future type, if it isn't already. +template +using futurize_t = typename futurize::type; + template class future { promise* _promise; From 422d642cf47c08711de41573aa2949fecefbb84e Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Fri, 6 Mar 2015 10:01:08 +0100 Subject: [PATCH 2/6] core: Add futurize::primise_type --- core/future.hh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/future.hh b/core/future.hh index 2a9c69022a..25ee4a1287 100644 --- a/core/future.hh +++ b/core/future.hh @@ -362,16 +362,19 @@ struct futurize; template struct futurize { using type = future; + using promise_type = promise; }; template <> struct futurize { using type = future<>; + using promise_type = promise<>; }; template struct futurize> { using type = future; + using promise_type = promise; }; // Converts a type to a future type, if it isn't already. From f25d7ac068927133eedfb5805c2491e8973cd93d Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Fri, 6 Mar 2015 10:01:25 +0100 Subject: [PATCH 3/6] core: Add futurize::apply() Invokes given function wrapping the result in a future if necessary. --- core/future.hh | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/core/future.hh b/core/future.hh index 25ee4a1287..8f92915097 100644 --- a/core/future.hh +++ b/core/future.hh @@ -363,18 +363,36 @@ template struct futurize { using type = future; using promise_type = promise; + + template + static inline type apply(Func&& func, std::tuple&& args); + + template + static inline type apply(Func&& func, FuncArgs&&... args); }; template <> struct futurize { using type = future<>; using promise_type = promise<>; + + template + static inline type apply(Func&& func, std::tuple&& args); + + template + static inline type apply(Func&& func, FuncArgs&&... args); }; template struct futurize> { using type = future; using promise_type = promise; + + template + static inline type apply(Func&& func, std::tuple&& args); + + template + static inline type apply(Func&& func, FuncArgs&&... args); }; // Converts a type to a future type, if it isn't already. @@ -721,4 +739,40 @@ future make_exception_future(Exception&& ex) noexcept { return make_exception_future(std::make_exception_ptr(std::forward(ex))); } +template +template +typename futurize::type futurize::apply(Func&& func, std::tuple&& args) { + return make_ready_future(::apply(std::forward(func), std::move(args))); +} + +template +template +typename futurize::type futurize::apply(Func&& func, FuncArgs&&... args) { + return make_ready_future(func(std::forward(args)...)); +} + +template +typename futurize::type futurize::apply(Func&& func, std::tuple&& args) { + ::apply(std::forward(func), std::move(args)); + return make_ready_future<>(); +} + +template +typename futurize::type futurize::apply(Func&& func, FuncArgs&&... args) { + func(std::forward(args)...); + return make_ready_future<>(); +} + +template +template +typename futurize>::type futurize>::apply(Func&& func, std::tuple&& args) { + return ::apply(std::forward(func), std::move(args)); +} + +template +template +typename futurize>::type futurize>::apply(Func&& func, FuncArgs&&... args) { + return func(std::forward(args)...); +} + #endif /* FUTURE_HH_ */ From a232b7e6c5da3004425fd02a511c88a092bcac12 Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Fri, 6 Mar 2015 10:02:24 +0100 Subject: [PATCH 4/6] core: Use futurize<> to unify future::then() specializations As a side benefit, returning non-void non-future is now allowed: future x() { return later().then([] { return 3; }); } --- core/future.hh | 48 ++++++++---------------------------------------- 1 file changed, 8 insertions(+), 40 deletions(-) diff --git a/core/future.hh b/core/future.hh index 8f92915097..aeaa7a6bf1 100644 --- a/core/future.hh +++ b/core/future.hh @@ -482,27 +482,23 @@ public: return state()->failed(); } - template - void then(Func, Enable) noexcept; - template - future<> then(Func&& func, - std::enable_if_t, void>::value, void*> = nullptr) noexcept { + futurize_t> then(Func&& func) noexcept { + using futurator = futurize>; 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), 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)] (auto& state) mutable { try { - apply(std::move(func), state.get()); - pr.set_value(); + futurator::apply(std::forward(func), state.get()).forward_to(std::move(pr)); } catch (...) { pr.set_exception(std::current_exception()); } @@ -520,34 +516,6 @@ public: } } - template - std::result_of_t - then(Func&& func, - std::enable_if_t>::value, void*> = nullptr) noexcept { - using P = typename std::result_of_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), 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 std::result_of_t)> then_wrapped(Func&& func, From af82e23c750c37f8b1c5c99fda778773949bd093 Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Fri, 6 Mar 2015 10:04:20 +0100 Subject: [PATCH 5/6] core: Use futurize<> to unify then_wrapped() specializations --- core/future.hh | 41 +++++++---------------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/core/future.hh b/core/future.hh index aeaa7a6bf1..b1ed4cd50d 100644 --- a/core/future.hh +++ b/core/future.hh @@ -517,13 +517,13 @@ public: } template - std::result_of_t)> - then_wrapped(Func&& func, - std::enable_if_t)>>::value, void*> = nullptr) && noexcept { - using P = typename std::result_of_t)>::promise_type; + futurize_t)>> + then_wrapped(Func&& func) && noexcept { + using futurator = futurize)>>; + using P = typename futurator::promise_type; if (state()->available()) { try { - return func(std::move(*this)); + return futurator::apply(std::forward(func), std::move(*this)); } catch (...) { P pr; pr.set_exception(std::current_exception()); @@ -534,35 +534,8 @@ public: auto next_fut = pr.get_future(); _promise->schedule([func = std::forward(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 - future<> - then_wrapped(Func&& func, - std::enable_if_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), pr = std::move(pr)] (auto& state) mutable { - try { - func(future(std::move(state))); - pr.set_value(); + futurator::apply(std::forward(func), future(std::move(state))) + .forward_to(std::move(pr)); } catch (...) { pr.set_exception(std::current_exception()); } From 7502f2a3a34caf63bb90bbea4f7910ddb49ea57d Mon Sep 17 00:00:00 2001 From: Tomasz Grabiec Date: Fri, 6 Mar 2015 10:06:46 +0100 Subject: [PATCH 6/6] tests: Add test for returning bare values from callbacks --- tests/futures_test.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/futures_test.cc b/tests/futures_test.cc index ffb270bb12..7d791f881d 100644 --- a/tests/futures_test.cc +++ b/tests/futures_test.cc @@ -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); + }); +}