From: Sven Over Date: Wed, 2 Sep 2015 10:13:17 +0000 (-0700) Subject: folly: specialise makeFutureWith for functions returning futures X-Git-Tag: deprecate-dynamic-initializer~442 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=823a8c0198d3f72b0cf6fa2efec8ba47d9a4d644;p=folly.git folly: specialise makeFutureWith for functions returning futures Summary: makeFutureWith executes a function and returns a future containing set to the function's return value. This diff adds a specialisation for the case when the function returns some type Future. Instead of returning Future>, makeFutureWith now just passes on the future that the function returned, which may or may not have a value set at this time. In case the function throws, makeFutureWith returns a Future containing the exception. With this diff, the following two lines produce equivalent results: auto f1 = makeFutureWith(func); auto f2 = makeFuture().then(func); except for the fact that f2 requires an additional temporary Future to be created and destroyed. Reviewed By: @fugalh Differential Revision: D2388335 --- diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h index fecf1781..eeb0e2e5 100644 --- a/folly/futures/Future-inl.h +++ b/folly/futures/Future-inl.h @@ -475,10 +475,32 @@ Future makeFuture() { return makeFuture(Unit{}); } +// makeFutureWith(Future()) -> Future template -auto makeFutureWith(F&& func) - -> Future::type> { - using LiftedResult = typename Unit::Lift::type; +typename std::enable_if::type>::value, + typename std::result_of::type>::type +makeFutureWith(F&& func) { + using InnerType = + typename isFuture::type>::Inner; + try { + return func(); + } catch (std::exception& e) { + return makeFuture( + exception_wrapper(std::current_exception(), e)); + } catch (...) { + return makeFuture(exception_wrapper(std::current_exception())); + } +} + +// makeFutureWith(T()) -> Future +// makeFutureWith(void()) -> Future +template +typename std::enable_if< + !(isFuture::type>::value), + Future::type>::type>>::type +makeFutureWith(F&& func) { + using LiftedResult = + typename Unit::Lift::type>::type; return makeFuture(makeTryWith([&func]() mutable { return func(); })); diff --git a/folly/futures/helpers.h b/folly/futures/helpers.h index 30e657c7..cf3e150b 100644 --- a/folly/futures/helpers.h +++ b/folly/futures/helpers.h @@ -75,11 +75,36 @@ Future::type> makeFuture(T&& t); /** Make a completed void Future. */ Future makeFuture(); -/** Make a completed Future by executing a function. If the function throws - we capture the exception, otherwise we capture the result. */ +/** + Make a Future by executing a function. + + If the function returns a value of type T, makeFutureWith + returns a completed Future, capturing the value returned + by the function. + + If the function returns a Future already, makeFutureWith + returns just that. + + Either way, if the function throws, a failed Future is + returned that captures the exception. + + Calling makeFutureWith(func) is equivalent to calling + makeFuture().then(func). +*/ + +// makeFutureWith(Future()) -> Future +template +typename std::enable_if::type>::value, + typename std::result_of::type>::type +makeFutureWith(F&& func); + +// makeFutureWith(T()) -> Future +// makeFutureWith(void()) -> Future template -auto makeFutureWith(F&& func) - -> Future::type>; +typename std::enable_if< + !(isFuture::type>::value), + Future::type>::type>>::type +makeFutureWith(F&& func); /// Make a failed Future from an exception_ptr. /// Because the Future's type cannot be inferred you have to specify it, e.g. diff --git a/folly/futures/test/FutureTest.cpp b/folly/futures/test/FutureTest.cpp index 16c9f1f9..cdec62e9 100644 --- a/folly/futures/test/FutureTest.cpp +++ b/folly/futures/test/FutureTest.cpp @@ -501,10 +501,20 @@ TEST(Future, makeFuture) { EXPECT_TYPE(makeFutureWith(fun), Future); EXPECT_EQ(42, makeFutureWith(fun).value()); + auto funf = [] { return makeFuture(43); }; + EXPECT_TYPE(makeFutureWith(funf), Future); + EXPECT_EQ(43, makeFutureWith(funf).value()); + auto failfun = []() -> int { throw eggs; }; EXPECT_TYPE(makeFutureWith(failfun), Future); + EXPECT_NO_THROW(makeFutureWith(failfun)); EXPECT_THROW(makeFutureWith(failfun).value(), eggs_t); + auto failfunf = []() -> Future { throw eggs; }; + EXPECT_TYPE(makeFutureWith(failfunf), Future); + EXPECT_NO_THROW(makeFutureWith(failfunf)); + EXPECT_THROW(makeFutureWith(failfunf).value(), eggs_t); + EXPECT_TYPE(makeFuture(), Future); }