From 4e907f707a04a334256b939acc6b810c0b882f86 Mon Sep 17 00:00:00 2001 From: Hans Fugal Date: Fri, 17 Apr 2015 10:41:45 -0700 Subject: [PATCH] then-with-Executor Summary: Pass an Executor to `then`, which applies only for that callback. This is on the one hand just a convenience method, but it's a major convenience when it's needed, because grabbing, storing, and restoring the old Executor in the middle of a chain is very inconvenient indeed. Test Plan: new unit Reviewed By: jsedgwick@fb.com Subscribers: robbert, exa, folly-diffs@, jsedgwick, nkgupta, yfeldblum, chalfant, davejwatson FB internal diff: D1985475 Signature: t1:1985475:1429148056:0450120263ba8110e8825420cbefe3b1887f7306 --- folly/futures/Future-inl.h | 10 ++++++++++ folly/futures/Future.h | 16 ++++++++++++++++ folly/futures/test/ViaTest.cpp | 30 ++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h index 7a2ffc2b..94930b7b 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 90207dd8..455c264e 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 390787d1..d17fe575 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); +} -- 2.34.1