then-with-Executor
authorHans Fugal <fugalh@fb.com>
Tue, 21 Apr 2015 23:52:06 +0000 (16:52 -0700)
committerAlecs King <int@fb.com>
Mon, 27 Apr 2015 23:48:56 +0000 (16:48 -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
docblock comments

Reviewed By: jsedgwick@fb.com

Subscribers: folly-diffs@, davejwatson, chalfant, yfeldblum, nkgupta, jsedgwick, exa, robbert

FB internal diff: D2011542

Tasks: 67715896838553

Signature: t1:2011542:1429660204:f5959b1e0b3b36dfb8c3c7091302d19101dde93b

folly/futures/Future-inl.h
folly/futures/Future.h
folly/futures/test/ViaTest.cpp

index 5bc6f58d82226c3fae115d952000213387674cd5..fb110d096e41a5324d542e0ae2a2fb2e7a46b4f2 100644 (file)
@@ -235,6 +235,19 @@ Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
   });
 }
 
+// TODO(6838553)
+#ifndef __clang__
+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);
+}
+#endif
+
 template <class T>
 Future<void> Future<T>::then() {
   return then([] (Try<T>&& t) {});
index 26555753ad361394a74188e98ccfb76e1fc3564d..4bd12403713e25611e90951c513308120ea3d70b 100644 (file)
@@ -335,6 +335,25 @@ class Future {
   Future<typename isFuture<R>::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 <class... Args>
+  auto then(Executor* x, Args&&... args)
+    -> decltype(this->then(std::forward<Args>(args)...));
+#endif
+
   /// Convenience method for ignoring the value and creating a Future<void>.
   /// Exceptions still propagate.
   Future<void> then();
index 390787d1e3f3395f0f0e6c0548f9e265e7e3f40c..0675baf8b3570169e2b4360120613c7b570aef1a 100644 (file)
@@ -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<void>) {} };
+  Foo f;
+  makeFuture().then(nullptr, &Foo::foo, &f);
+}
+#endif