From cd338595aadfd2fa7b545a7507ecdb59b81e88ab Mon Sep 17 00:00:00 2001 From: Hans Fugal Date: Tue, 21 Apr 2015 16:52:06 -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 docblock comments Reviewed By: jsedgwick@fb.com Subscribers: folly-diffs@, davejwatson, chalfant, yfeldblum, nkgupta, jsedgwick, exa, robbert FB internal diff: D2011542 Tasks: 6771589, 6838553 Signature: t1:2011542:1429660204:f5959b1e0b3b36dfb8c3c7091302d19101dde93b --- folly/futures/Future-inl.h | 13 +++++++++++++ folly/futures/Future.h | 19 +++++++++++++++++++ folly/futures/test/ViaTest.cpp | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/folly/futures/Future-inl.h b/folly/futures/Future-inl.h index 5bc6f58d..fb110d09 100644 --- a/folly/futures/Future-inl.h +++ b/folly/futures/Future-inl.h @@ -235,6 +235,19 @@ Future::then(R(Caller::*func)(Args...), Caller *instance) { }); } +// TODO(6838553) +#ifndef __clang__ +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); +} +#endif + template Future Future::then() { return then([] (Try&& t) {}); diff --git a/folly/futures/Future.h b/folly/futures/Future.h index 26555753..4bd12403 100644 --- a/folly/futures/Future.h +++ b/folly/futures/Future.h @@ -335,6 +335,25 @@ class Future { Future::Inner> then(R(Caller::*func)(Args...), Caller *instance); +// TODO(6838553) +#ifndef __clang__ + /// 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)...)); +#endif + /// 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..0675baf8 100644 --- a/folly/futures/test/ViaTest.cpp +++ b/folly/futures/test/ViaTest.cpp @@ -184,3 +184,36 @@ TEST(Via, chain3) { EXPECT_EQ(42, f.get()); EXPECT_EQ(3, count); } + +// TODO(6838553) +#ifndef __clang__ +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); +} +#endif -- 2.34.1