diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h index 7a2ffc2..94930b7 100644 --- a/folly/futures/Future-inl.h +++ b/folly/futures/Future-inl.h @@ -235,6 +235,16 @@ Future::then(R(Caller::*func)(Args...), Caller *instance) { }); } +template +template +auto Future::then(Executor* x, Args&&... args) + -> decltype(this->then(std::forward(args)...)) +{ + auto oldX = getExecutor(); + setExecutor(x); + return this->then(std::forward(args)...).via(oldX); +} + template Future Future::then() { return then([] (Try&& t) {}); diff --git a/folly/futures/Future.h b/folly/futures/Future.h index 90207dd..455c264 100644 --- a/folly/futures/Future.h +++ b/folly/futures/Future.h @@ -325,6 +325,22 @@ class Future { Future::Inner> then(R(Caller::*func)(Args...), Caller *instance); + /// Execute the callback via the given Executor. The executor doesn't stick. + /// + /// Contrast + /// + /// f.via(x).then(b).then(c) + /// + /// with + /// + /// f.then(x, b).then(c) + /// + /// In the former both b and c execute via x. In the latter, only b executes + /// via x, and c executes via the same executor (if any) that f had. + template + auto then(Executor* x, Args&&... args) + -> decltype(this->then(std::forward(args)...)); + /// Convenience method for ignoring the value and creating a Future. /// Exceptions still propagate. Future then(); diff --git a/folly/futures/test/ViaTest.cpp b/folly/futures/test/ViaTest.cpp index 390787d..d17fe57 100644 --- a/folly/futures/test/ViaTest.cpp +++ b/folly/futures/test/ViaTest.cpp @@ -184,3 +184,33 @@ TEST(Via, chain3) { EXPECT_EQ(42, f.get()); EXPECT_EQ(3, count); } + +TEST(Via, then2) { + ManualExecutor x1, x2; + bool a,b,c; + via(&x1) + .then([&]{ a = true; }) + .then(&x2, [&]{ b = true; }) + .then([&]{ c = true; }); + + EXPECT_FALSE(a); + EXPECT_FALSE(b); + + x1.run(); + EXPECT_TRUE(a); + EXPECT_FALSE(b); + EXPECT_FALSE(c); + + x2.run(); + EXPECT_TRUE(b); + EXPECT_FALSE(c); + + x1.run(); + EXPECT_TRUE(c); +} + +TEST(Via, then2Variadic) { + struct Foo { void foo(Try) {} }; + Foo f; + makeFuture().then(nullptr, &Foo::foo, &f); +}