Commit 823a8c01 authored by Sven Over's avatar Sven Over Committed by facebook-github-bot-4

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<T>. Instead
of returning Future<Future<T>>, 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<T> 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<Unit> to be created and destroyed.

Reviewed By: @fugalh

Differential Revision: D2388335
parent f1190644
......@@ -475,10 +475,32 @@ Future<Unit> makeFuture() {
return makeFuture(Unit{});
}
// makeFutureWith(Future<T>()) -> Future<T>
template <class F>
auto makeFutureWith(F&& func)
-> Future<typename Unit::Lift<decltype(func())>::type> {
using LiftedResult = typename Unit::Lift<decltype(func())>::type;
typename std::enable_if<isFuture<typename std::result_of<F()>::type>::value,
typename std::result_of<F()>::type>::type
makeFutureWith(F&& func) {
using InnerType =
typename isFuture<typename std::result_of<F()>::type>::Inner;
try {
return func();
} catch (std::exception& e) {
return makeFuture<InnerType>(
exception_wrapper(std::current_exception(), e));
} catch (...) {
return makeFuture<InnerType>(exception_wrapper(std::current_exception()));
}
}
// makeFutureWith(T()) -> Future<T>
// makeFutureWith(void()) -> Future<Unit>
template <class F>
typename std::enable_if<
!(isFuture<typename std::result_of<F()>::type>::value),
Future<typename Unit::Lift<typename std::result_of<F()>::type>::type>>::type
makeFutureWith(F&& func) {
using LiftedResult =
typename Unit::Lift<typename std::result_of<F()>::type>::type;
return makeFuture<LiftedResult>(makeTryWith([&func]() mutable {
return func();
}));
......
......@@ -75,11 +75,36 @@ Future<typename std::decay<T>::type> makeFuture(T&& t);
/** Make a completed void Future. */
Future<Unit> 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<T>, capturing the value returned
by the function.
If the function returns a Future<T> 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<T>()) -> Future<T>
template <class F>
typename std::enable_if<isFuture<typename std::result_of<F()>::type>::value,
typename std::result_of<F()>::type>::type
makeFutureWith(F&& func);
// makeFutureWith(T()) -> Future<T>
// makeFutureWith(void()) -> Future<Unit>
template <class F>
auto makeFutureWith(F&& func)
-> Future<typename Unit::Lift<decltype(func())>::type>;
typename std::enable_if<
!(isFuture<typename std::result_of<F()>::type>::value),
Future<typename Unit::Lift<typename std::result_of<F()>::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.
......
......@@ -501,10 +501,20 @@ TEST(Future, makeFuture) {
EXPECT_TYPE(makeFutureWith(fun), Future<int>);
EXPECT_EQ(42, makeFutureWith(fun).value());
auto funf = [] { return makeFuture<int>(43); };
EXPECT_TYPE(makeFutureWith(funf), Future<int>);
EXPECT_EQ(43, makeFutureWith(funf).value());
auto failfun = []() -> int { throw eggs; };
EXPECT_TYPE(makeFutureWith(failfun), Future<int>);
EXPECT_NO_THROW(makeFutureWith(failfun));
EXPECT_THROW(makeFutureWith(failfun).value(), eggs_t);
auto failfunf = []() -> Future<int> { throw eggs; };
EXPECT_TYPE(makeFutureWith(failfunf), Future<int>);
EXPECT_NO_THROW(makeFutureWith(failfunf));
EXPECT_THROW(makeFutureWith(failfunf).value(), eggs_t);
EXPECT_TYPE(makeFuture(), Future<Unit>);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment