Commit d167b415 authored by Hans Fugal's avatar Hans Fugal Committed by Sara Golemon

folly::via(Executor*, Func)

Summary: ((not yet) more performant) sugar for `via(&x).then(func)`

Reviewed By: @​hannesr

Differential Revision: D2131246
parent 60825c9b
......@@ -435,6 +435,17 @@ inline Future<T> Future<T>::via(Executor* executor, int8_t priority) & {
return std::move(f).via(executor, priority);
}
template <class Func>
auto via(Executor* x, Func func)
-> Future<typename isFuture<decltype(func())>::Inner>
// this would work, if not for Future<void> :-/
// -> decltype(via(x).then(func))
{
// TODO make this actually more performant. :-P #7260175
return via(x).then(func);
}
template <class T>
bool Future<T>::isReady() const {
throwIfInvalid();
......
......@@ -56,7 +56,7 @@ namespace futures {
return map(c.begin(), c.end(), std::forward<F>(func));
}
}
} // namespace futures
/**
Make a completed Future by moving in a value. e.g.
......@@ -124,6 +124,13 @@ inline Future<void> via(
Executor* executor,
int8_t priority = Executor::MID_PRI);
/// Execute a function via the given executor and return a future.
/// This is semantically equivalent to via(executor).then(func), but
/// easier to read and slightly more efficient.
template <class Func>
auto via(Executor*, Func func)
-> Future<typename isFuture<decltype(func())>::Inner>;
/** When all the input Futures complete, the returned Future will complete.
Errors do not cause early termination; this Future will always succeed
after all its Futures have finished (whether successfully or with an
......@@ -286,4 +293,4 @@ auto unorderedReduce(Collection&& c, T&& initial, F&& func)
std::forward<F>(func));
}
} // namespace folly
} // namespace
......@@ -415,7 +415,7 @@ TEST(Via, viaRaces) {
t2.join();
}
TEST(Future, callbackRace) {
TEST(Via, callbackRace) {
ThreadExecutor x;
auto fn = [&x]{
......@@ -441,3 +441,52 @@ TEST(Future, callbackRace) {
fn().wait();
}
TEST(ViaFunc, liftsVoid) {
ManualExecutor x;
int count = 0;
Future<void> f = via(&x, [&]{ count++; });
EXPECT_EQ(0, count);
x.run();
EXPECT_EQ(1, count);
}
TEST(ViaFunc, value) {
ManualExecutor x;
EXPECT_EQ(42, via(&x, []{ return 42; }).getVia(&x));
}
TEST(ViaFunc, exception) {
ManualExecutor x;
EXPECT_THROW(
via(&x, []() -> int { throw std::runtime_error("expected"); })
.getVia(&x),
std::runtime_error);
}
TEST(ViaFunc, future) {
ManualExecutor x;
EXPECT_EQ(42, via(&x, []{ return makeFuture(42); })
.getVia(&x));
}
TEST(ViaFunc, voidFuture) {
ManualExecutor x;
int count = 0;
via(&x, [&]{ count++; }).getVia(&x);
EXPECT_EQ(1, count);
}
TEST(ViaFunc, isSticky) {
ManualExecutor x;
int count = 0;
auto f = via(&x, [&]{ count++; });
x.run();
f.then([&]{ count++; });
EXPECT_EQ(1, count);
x.run();
EXPECT_EQ(2, count);
}
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