From ca71b787508ff68e25dfdf0e762d8a8722573141 Mon Sep 17 00:00:00 2001 From: Hannes Roth Date: Mon, 26 Jan 2015 12:53:42 -0800 Subject: [PATCH] (Wangle) Then Magic Summary: All is good now. Test Plan: Run all the tests. Reviewed By: hans@fb.com Subscribers: jsedgwick, trunkagent, fugalh, folly-diffs@ FB internal diff: D1758272 Signature: t1:1758272:1421889405:a015d30783715e106a1e6667e971f7cf47c8392d --- folly/futures/Future-inl.h | 189 +++---------------- folly/futures/Future.h | 290 +++++++++++------------------- folly/futures/Try.h | 15 ++ folly/futures/test/FutureTest.cpp | 38 ++++ folly/futures/test/ThenTest.cpp | 169 +++++++++++++++++ folly/futures/test/Thens.cpp | 66 ++++++- folly/futures/test/Thens.h | 10 -- folly/futures/test/thens.rb | 46 +++-- 8 files changed, 437 insertions(+), 386 deletions(-) create mode 100644 folly/futures/test/ThenTest.cpp diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h index e14754b7..e95b4a1f 100644 --- a/folly/futures/Future-inl.h +++ b/folly/futures/Future-inl.h @@ -31,16 +31,6 @@ namespace detail { Timekeeper* getTimekeeperSingleton(); } -template -struct isFuture { - static const bool value = false; -}; - -template -struct isFuture > { - static const bool value = true; -}; - template Future::Future(Future&& other) noexcept : core_(nullptr) { *this = std::move(other); @@ -78,14 +68,14 @@ void Future::setCallback_(F&& func) { core_->setCallback(std::move(func)); } -// Variant: f.then([](Try&& t){ return t.value(); }); +// Variant: returns a value +// e.g. f.then([](Try&& t){ return t.value(); }); template -template -typename std::enable_if< - !isFuture&&)>::type>::value, - Future&&)>::type> >::type -Future::then(F&& func) { - typedef typename std::result_of&&)>::type B; +template +typename std::enable_if::type +Future::thenImplementation(F func, detail::argResult) { + static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument"); + typedef typename R::ReturnsFuture::Inner B; throwIfInvalid(); @@ -130,39 +120,11 @@ Future::then(F&& func) { */ setCallback_( [p, funcm](Try&& t) mutable { - p->fulfil([&]() { - return (*funcm)(std::move(t)); - }); - }); - - return f; -} - -// Variant: f.then([](T&& t){ return t; }); -template -template -typename std::enable_if< - !std::is_same::value && - !isFuture::type&&)>::type>::value, - Future::type&&)>::type> >::type -Future::then(F&& func) { - typedef typename std::result_of::type B; - - throwIfInvalid(); - - folly::MoveWrapper> p; - folly::MoveWrapper funcm(std::forward(func)); - auto f = p->getFuture(); - - setCallback_( - [p, funcm](Try&& t) mutable { - if (t.hasException()) { + if (!isTry && t.hasException()) { p->setException(std::move(t.exception())); } else { p->fulfil([&]() { - return (*funcm)(std::move(t.value())); + return (*funcm)(t.template get()...); }); } }); @@ -170,44 +132,14 @@ Future::then(F&& func) { return f; } -// Variant: f.then([](){ return; }); +// Variant: returns a Future +// e.g. f.then([](T&& t){ return makeFuture(t); }); template -template -typename std::enable_if< - std::is_same::value && - !isFuture::type>::value, - Future::type> >::type -Future::then(F&& func) { - typedef typename std::result_of::type B; - - throwIfInvalid(); - - folly::MoveWrapper> p; - folly::MoveWrapper funcm(std::forward(func)); - auto f = p->getFuture(); - - setCallback_( - [p, funcm](Try&& t) mutable { - if (t.hasException()) { - p->setException(std::move(t.exception())); - } else { - p->fulfil([&]() { - return (*funcm)(); - }); - } - }); - - return f; -} - -// Variant: f.then([](Try&& t){ return makeFuture(t.value()); }); -template -template -typename std::enable_if< - isFuture&&)>::type>::value, - Future&&)>::type::value_type> >::type -Future::then(F&& func) { - typedef typename std::result_of&&)>::type::value_type B; +template +typename std::enable_if::type +Future::thenImplementation(F func, detail::argResult) { + static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument"); + typedef typename R::ReturnsFuture::Inner B; throwIfInvalid(); @@ -220,53 +152,16 @@ Future::then(F&& func) { setCallback_( [p, funcm](Try&& t) mutable { - try { - auto f2 = (*funcm)(std::move(t)); - // that didn't throw, now we can steal p - f2.setCallback_([p](Try&& b) mutable { - p->fulfilTry(std::move(b)); - }); - } catch (const std::exception& e) { - p->setException(exception_wrapper(std::current_exception(), e)); - } catch (...) { - p->setException(exception_wrapper(std::current_exception())); - } - }); - - return f; -} - -// Variant: f.then([](T&& t){ return makeFuture(t); }); -template -template -typename std::enable_if< - !std::is_same::value && - isFuture::type&&)>::type>::value, - Future::type&&)>::type::value_type> >::type -Future::then(F&& func) { - typedef typename std::result_of::type::value_type B; - - throwIfInvalid(); - - folly::MoveWrapper> p; - folly::MoveWrapper funcm(std::forward(func)); - auto f = p->getFuture(); - - setCallback_( - [p, funcm](Try&& t) mutable { - if (t.hasException()) { + if (!isTry && t.hasException()) { p->setException(std::move(t.exception())); } else { try { - auto f2 = (*funcm)(std::move(t.value())); + auto f2 = (*funcm)(t.template get()...); + // that didn't throw, now we can steal p f2.setCallback_([p](Try&& b) mutable { p->fulfilTry(std::move(b)); }); } catch (const std::exception& e) { - p->setException(exception_wrapper(std::current_exception(), e)); - } catch (...) { p->setException(exception_wrapper(std::current_exception())); } } @@ -275,42 +170,16 @@ Future::then(F&& func) { return f; } -// Variant: f.then([](){ return makeFuture(); }); -template -template -typename std::enable_if< - std::is_same::value && - isFuture::type>::value, - Future::type::value_type> >::type -Future::then(F&& func) { - typedef typename std::result_of::type::value_type B; - - throwIfInvalid(); - - folly::MoveWrapper> p; - folly::MoveWrapper funcm(std::forward(func)); - - auto f = p->getFuture(); - - setCallback_( - [p, funcm](Try&& t) mutable { - if (t.hasException()) { - p->setException(t.exception()); - } else { - try { - auto f2 = (*funcm)(); - f2.setCallback_([p](Try&& b) mutable { - p->fulfilTry(std::move(b)); - }); - } catch (const std::exception& e) { - p->setException(exception_wrapper(std::current_exception(), e)); - } catch (...) { - p->setException(exception_wrapper(std::current_exception())); - } - } - }); - - return f; +template +template + Future::Inner> +Future::then(Caller *instance, R(Caller::*func)(Args...)) { + typedef typename std::remove_cv< + typename std::remove_reference< + typename detail::ArgType::FirstArg>::type>::type FirstArg; + return then([instance, func](Try&& t){ + return (instance->*func)(t.template get::value, Args>()...); + }); } template diff --git a/folly/futures/Future.h b/folly/futures/Future.h index 948e263a..0f406d76 100644 --- a/folly/futures/Future.h +++ b/folly/futures/Future.h @@ -35,29 +35,29 @@ namespace folly { template struct Promise; -namespace detail { - -template struct Core; -template struct VariadicContext; +template +struct isFuture : std::false_type { + typedef T Inner; +}; -template -struct AliasIfVoid { - typedef typename std::conditional< - std::is_same::value, - int, - T>::type type; +template +struct isFuture> : std::true_type { + typedef T Inner; }; +template +struct isTry : std::false_type {}; template -struct IsFuture : std::integral_constant { - typedef T Inner; -}; +struct isTry> : std::true_type {}; -template