then-with-Executor
authorHans Fugal <fugalh@fb.com>
Fri, 17 Apr 2015 17:41:45 +0000 (10:41 -0700)
committerAlecs King <int@fb.com>
Mon, 27 Apr 2015 23:45:33 +0000 (16:45 -0700)
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
folly/futures/Future.h
folly/futures/test/ViaTest.cpp

index 7a2ffc2b3263351118babc339109faff788af01a..94930b7b965125e05dddb2cd0b0f423b7a51471f 100644 (file)
@@ -235,6 +235,16 @@ Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
   });
 }
 
+template <class T>
+template <class... Args>
+auto Future<T>::then(Executor* x, Args&&... args)
+  -> decltype(this->then(std::forward<Args>(args)...))
+{
+  auto oldX = getExecutor();
+  setExecutor(x);
+  return this->then(std::forward<Args>(args)...).via(oldX);
+}
+
 template <class T>
 Future<void> Future<T>::then() {
   return then([] (Try<T>&& t) {});
index 90207dd8a1000a807b9a18a9ba99b1d17d2a2934..455c264e7be1e164b96c59f67738c180fd461ac8 100644 (file)
@@ -325,6 +325,22 @@ class Future {
   Future<typename isFuture<R>::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 <class... Args>
+  auto then(Executor* x, Args&&... args)
+    -> decltype(this->then(std::forward<Args>(args)...));
+
   /// Convenience method for ignoring the value and creating a Future<void>.
   /// Exceptions still propagate.
   Future<void> then();
index 390787d1e3f3395f0f0e6c0548f9e265e7e3f40c..d17fe575c6324ff4d85874f3c596f23906b99a73 100644 (file)
@@ -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<void>) {} };
+  Foo f;
+  makeFuture().then(nullptr, &Foo::foo, &f);
+}