Commit c316166d authored by Lee Howes's avatar Lee Howes Committed by Facebook Github Bot

Add executor-taking forms of deferValue and thenValue

Summary: For consistency adds thenExValue and deferExValue.

Reviewed By: yfeldblum

Differential Revision: D14793864

fbshipit-source-id: 700f02cfb27b93e1739c511f01142c30c1896990
parent 57cc7e45
...@@ -929,6 +929,23 @@ SemiFuture<T>::deferValue(F&& func) && { ...@@ -929,6 +929,23 @@ SemiFuture<T>::deferValue(F&& func) && {
}); });
} }
template <class T>
template <typename F>
SemiFuture<
typename futures::detail::valueExecutorCallableResult<T, F>::value_type>
SemiFuture<T>::deferExValue(F&& func) && {
return std::move(*this).deferExTry(
[f = std::forward<F>(func)](
folly::Executor::KeepAlive<> ka, folly::Try<T>&& t) mutable {
return std::forward<F>(f)(
ka,
t.template get<
false,
typename futures::detail::valueExecutorCallableResult<T, F>::
ValueArg>());
});
}
template <class T> template <class T>
template <class ExceptionType, class F> template <class ExceptionType, class F>
SemiFuture<T> SemiFuture<T>::deferError(tag_t<ExceptionType>, F&& func) && { SemiFuture<T> SemiFuture<T>::deferError(tag_t<ExceptionType>, F&& func) && {
...@@ -1126,6 +1143,28 @@ Future<T>::thenValue(F&& func) && { ...@@ -1126,6 +1143,28 @@ Future<T>::thenValue(F&& func) && {
return this->thenImplementation(std::move(lambdaFunc), R{}); return this->thenImplementation(std::move(lambdaFunc), R{});
} }
template <class T>
template <typename F>
Future<typename futures::detail::valueExecutorCallableResult<T, F>::value_type>
Future<T>::thenExValue(F&& func) && {
// As Futures may carry null executors, ensure that what we pass into the
// continuation is always usable by replacing with inline if necessary.
auto ka = getKeepAliveToken(this->getExecutor());
// Enforce that executor cannot be null
DCHECK(ka);
auto lambdaFunc = [f = std::forward<F>(func),
exec = std::move(ka)](folly::Try<T>&& t) mutable {
return std::forward<F>(f)(
exec,
t.template get<
false,
typename futures::detail::valueExecutorCallableResult<T, F>::
ValueArg>());
};
using R = futures::detail::tryCallableResult<T, decltype(lambdaFunc)>;
return this->thenImplementation(std::move(lambdaFunc), R{});
}
template <class T> template <class T>
template <class ExceptionType, class F> template <class ExceptionType, class F>
typename std::enable_if< typename std::enable_if<
......
...@@ -93,6 +93,7 @@ struct ArgType; ...@@ -93,6 +93,7 @@ struct ArgType;
template <typename Arg, typename... Args> template <typename Arg, typename... Args>
struct ArgType<Arg, Args...> { struct ArgType<Arg, Args...> {
typedef Arg FirstArg; typedef Arg FirstArg;
typedef ArgType<Args...> Tail;
}; };
template <> template <>
...@@ -156,6 +157,15 @@ struct valueCallableResult { ...@@ -156,6 +157,15 @@ struct valueCallableResult {
typedef Future<value_type> Return; typedef Future<value_type> Return;
}; };
template <typename T, typename F>
struct valueExecutorCallableResult {
typedef detail::argResult<false, F, const Executor::KeepAlive<>&, T&&> Arg;
typedef isFutureOrSemiFuture<typename Arg::Result> ReturnsFuture;
typedef typename ReturnsFuture::Inner value_type;
typedef typename Arg::ArgList::Tail::FirstArg ValueArg;
typedef Future<value_type> Return;
};
template <typename L> template <typename L>
struct Extract : Extract<decltype(&L::operator())> {}; struct Extract : Extract<decltype(&L::operator())> {};
......
...@@ -707,6 +707,11 @@ class SemiFuture : private futures::detail::FutureBase<T> { ...@@ -707,6 +707,11 @@ class SemiFuture : private futures::detail::FutureBase<T> {
SemiFuture<typename futures::detail::valueCallableResult<T, F>::value_type> SemiFuture<typename futures::detail::valueCallableResult<T, F>::value_type>
deferValue(F&& func) &&; deferValue(F&& func) &&;
template <typename F>
SemiFuture<
typename futures::detail::valueExecutorCallableResult<T, F>::value_type>
deferExValue(F&& func) &&;
template <typename R, typename... Args> template <typename R, typename... Args>
auto deferValue(R (&func)(Args...)) && { auto deferValue(R (&func)(Args...)) && {
return std::move(*this).deferValue(&func); return std::move(*this).deferValue(&func);
...@@ -1295,6 +1300,11 @@ class Future : private futures::detail::FutureBase<T> { ...@@ -1295,6 +1300,11 @@ class Future : private futures::detail::FutureBase<T> {
Future<typename futures::detail::valueCallableResult<T, F>::value_type> Future<typename futures::detail::valueCallableResult<T, F>::value_type>
thenValue(F&& func) &&; thenValue(F&& func) &&;
template <typename F>
Future<
typename futures::detail::valueExecutorCallableResult<T, F>::value_type>
thenExValue(F&& func) &&;
template <typename R, typename... Args> template <typename R, typename... Args>
auto thenValue(R (&func)(Args...)) && { auto thenValue(R (&func)(Args...)) && {
return std::move(*this).thenValue(&func); return std::move(*this).thenValue(&func);
......
...@@ -1065,6 +1065,16 @@ TEST(Future, thenValue) { ...@@ -1065,6 +1065,16 @@ TEST(Future, thenValue) {
EXPECT_THROW(f.value(), eggs_t); EXPECT_THROW(f.value(), eggs_t);
} }
TEST(Future, ThenValueWithExecutor) {
ManualExecutor executor;
auto sf = makeFuture(42).via(&executor).thenExValue(
[&](const Executor::KeepAlive<>& e, int val) {
EXPECT_EQ(&executor, e.get());
EXPECT_EQ(val, 42);
});
std::move(sf).getVia(&executor);
}
TEST(Future, thenValueFuture) { TEST(Future, thenValueFuture) {
bool flag = false; bool flag = false;
makeFuture<int>(42) makeFuture<int>(42)
......
...@@ -1179,6 +1179,16 @@ TEST(SemiFuture, DeferWithExecutor) { ...@@ -1179,6 +1179,16 @@ TEST(SemiFuture, DeferWithExecutor) {
std::move(sf).via(&executor).getVia(&executor); std::move(sf).via(&executor).getVia(&executor);
} }
TEST(SemiFuture, DeferValueWithExecutor) {
ManualExecutor executor;
auto sf = makeSemiFuture(42).deferExValue(
[&](const Executor::KeepAlive<>& e, int val) {
EXPECT_EQ(&executor, e.get());
EXPECT_EQ(val, 42);
});
std::move(sf).via(&executor).getVia(&executor);
}
TEST(SemiFuture, within) { TEST(SemiFuture, within) {
{ {
auto sf = makeSemiFuture(42) auto sf = makeSemiFuture(42)
......
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