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) && {
});
}
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 ExceptionType, class F>
SemiFuture<T> SemiFuture<T>::deferError(tag_t<ExceptionType>, F&& func) && {
......@@ -1126,6 +1143,28 @@ Future<T>::thenValue(F&& func) && {
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 ExceptionType, class F>
typename std::enable_if<
......
......@@ -93,6 +93,7 @@ struct ArgType;
template <typename Arg, typename... Args>
struct ArgType<Arg, Args...> {
typedef Arg FirstArg;
typedef ArgType<Args...> Tail;
};
template <>
......@@ -156,6 +157,15 @@ struct valueCallableResult {
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>
struct Extract : Extract<decltype(&L::operator())> {};
......
......@@ -707,6 +707,11 @@ class SemiFuture : private futures::detail::FutureBase<T> {
SemiFuture<typename futures::detail::valueCallableResult<T, F>::value_type>
deferValue(F&& func) &&;
template <typename F>
SemiFuture<
typename futures::detail::valueExecutorCallableResult<T, F>::value_type>
deferExValue(F&& func) &&;
template <typename R, typename... Args>
auto deferValue(R (&func)(Args...)) && {
return std::move(*this).deferValue(&func);
......@@ -1295,6 +1300,11 @@ class Future : private futures::detail::FutureBase<T> {
Future<typename futures::detail::valueCallableResult<T, F>::value_type>
thenValue(F&& func) &&;
template <typename F>
Future<
typename futures::detail::valueExecutorCallableResult<T, F>::value_type>
thenExValue(F&& func) &&;
template <typename R, typename... Args>
auto thenValue(R (&func)(Args...)) && {
return std::move(*this).thenValue(&func);
......
......@@ -1065,6 +1065,16 @@ TEST(Future, thenValue) {
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) {
bool flag = false;
makeFuture<int>(42)
......
......@@ -1179,6 +1179,16 @@ TEST(SemiFuture, DeferWithExecutor) {
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) {
{
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