Commit e4e2520a authored by Hannes Roth's avatar Hannes Roth Committed by Praveen Kumar Ramakrishnan

(Wangle) Fix Executor problem

Summary:
None of these functions should be templated with `class Executor`.
Except `then(Executor, Args...)` because otherwise the compiler gets
confused. This was the combination that worked for both Clang and GCC,
don't ask me why. I'm assuming this puts it on a low priority...

I think this is also OK, because `setExecutor` takes an actual
`folly::Executor`, so even `then(Executor, Args...)` won't just work for any
`Executor`.

Test Plan: Run all the tests.

Reviewed By: jsedgwick@fb.com

Subscribers: folly-diffs@, jsedgwick, yfeldblum, chalfant

FB internal diff: D2036912

Tasks: 6838553

Signature: t1:2036912:1430493088:44f2ffe146298c3f978ac27a45b9b2e33b2b0422
parent e9089c4a
...@@ -226,18 +226,17 @@ Future<T>::then(R(Caller::*func)(Args...), Caller *instance) { ...@@ -226,18 +226,17 @@ Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
}); });
} }
// TODO(6838553)
#ifndef __clang__
template <class T> template <class T>
template <class... Args> template <class Executor, class Arg, class... Args>
auto Future<T>::then(Executor* x, Args&&... args) auto Future<T>::then(Executor* x, Arg&& arg, Args&&... args)
-> decltype(this->then(std::forward<Args>(args)...)) -> decltype(this->then(std::forward<Arg>(arg),
std::forward<Args>(args)...))
{ {
auto oldX = getExecutor(); auto oldX = getExecutor();
setExecutor(x); setExecutor(x);
return this->then(std::forward<Args>(args)...).via(oldX); return this->then(std::forward<Arg>(arg), std::forward<Args>(args)...).
via(oldX);
} }
#endif
template <class T> template <class T>
Future<void> Future<T>::then() { Future<void> Future<T>::then() {
...@@ -424,7 +423,6 @@ Optional<Try<T>> Future<T>::poll() { ...@@ -424,7 +423,6 @@ Optional<Try<T>> Future<T>::poll() {
} }
template <class T> template <class T>
template <typename Executor>
inline Future<T> Future<T>::via(Executor* executor) && { inline Future<T> Future<T>::via(Executor* executor) && {
throwIfInvalid(); throwIfInvalid();
...@@ -434,7 +432,6 @@ inline Future<T> Future<T>::via(Executor* executor) && { ...@@ -434,7 +432,6 @@ inline Future<T> Future<T>::via(Executor* executor) && {
} }
template <class T> template <class T>
template <typename Executor>
inline Future<T> Future<T>::via(Executor* executor) & { inline Future<T> Future<T>::via(Executor* executor) & {
throwIfInvalid(); throwIfInvalid();
...@@ -530,8 +527,7 @@ inline Future<void> makeFuture(Try<void>&& t) { ...@@ -530,8 +527,7 @@ inline Future<void> makeFuture(Try<void>&& t) {
} }
// via // via
template <typename Executor> inline Future<void> via(Executor* executor) {
Future<void> via(Executor* executor) {
return makeFuture().via(executor); return makeFuture().via(executor);
} }
......
...@@ -97,14 +97,12 @@ class Future { ...@@ -97,14 +97,12 @@ class Future {
// The ref-qualifier allows for `this` to be moved out so we // The ref-qualifier allows for `this` to be moved out so we
// don't get access-after-free situations in chaining. // don't get access-after-free situations in chaining.
// https://akrzemi1.wordpress.com/2014/06/02/ref-qualifiers/ // https://akrzemi1.wordpress.com/2014/06/02/ref-qualifiers/
template <typename Executor> inline Future<T> via(Executor* executor) &&;
Future<T> via(Executor* executor) &&;
/// This variant creates a new future, where the ref-qualifier && version /// This variant creates a new future, where the ref-qualifier && version
/// moves `this` out. This one is less efficient but avoids confusing users /// moves `this` out. This one is less efficient but avoids confusing users
/// when "return f.via(x);" fails. /// when "return f.via(x);" fails.
template <typename Executor> inline Future<T> via(Executor* executor) &;
Future<T> via(Executor* executor) &;
/** True when the result (or exception) is ready. */ /** True when the result (or exception) is ready. */
bool isReady() const; bool isReady() const;
...@@ -182,8 +180,6 @@ class Future { ...@@ -182,8 +180,6 @@ class Future {
Future<typename isFuture<R>::Inner> Future<typename isFuture<R>::Inner>
then(R(Caller::*func)(Args...), Caller *instance); then(R(Caller::*func)(Args...), Caller *instance);
// TODO(6838553)
#ifndef __clang__
/// Execute the callback via the given Executor. The executor doesn't stick. /// Execute the callback via the given Executor. The executor doesn't stick.
/// ///
/// Contrast /// Contrast
...@@ -196,10 +192,10 @@ class Future { ...@@ -196,10 +192,10 @@ class Future {
/// ///
/// In the former both b and c execute via x. In the latter, only b executes /// 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. /// via x, and c executes via the same executor (if any) that f had.
template <class... Args> template <class Executor, class Arg, class... Args>
auto then(Executor* x, Args&&... args) auto then(Executor* x, Arg&& arg, Args&&... args)
-> decltype(this->then(std::forward<Args>(args)...)); -> decltype(this->then(std::forward<Arg>(arg),
#endif std::forward<Args>(args)...));
/// Convenience method for ignoring the value and creating a Future<void>. /// Convenience method for ignoring the value and creating a Future<void>.
/// Exceptions still propagate. /// Exceptions still propagate.
......
...@@ -131,8 +131,7 @@ Future<T> makeFuture(Try<T>&& t); ...@@ -131,8 +131,7 @@ Future<T> makeFuture(Try<T>&& t);
* *
* @returns a void Future that will call back on the given executor * @returns a void Future that will call back on the given executor
*/ */
template <typename Executor> inline Future<void> via(Executor* executor);
Future<void> via(Executor* executor);
/** When all the input Futures complete, the returned Future will complete. /** When all the input Futures complete, the returned Future will complete.
Errors do not cause early termination; this Future will always succeed Errors do not cause early termination; this Future will always succeed
......
...@@ -185,11 +185,9 @@ TEST(Via, chain3) { ...@@ -185,11 +185,9 @@ TEST(Via, chain3) {
EXPECT_EQ(3, count); EXPECT_EQ(3, count);
} }
// TODO(6838553)
#ifndef __clang__
TEST(Via, then2) { TEST(Via, then2) {
ManualExecutor x1, x2; ManualExecutor x1, x2;
bool a,b,c; bool a = false, b = false, c = false;
via(&x1) via(&x1)
.then([&]{ a = true; }) .then([&]{ a = true; })
.then(&x2, [&]{ b = true; }) .then(&x2, [&]{ b = true; })
...@@ -212,8 +210,11 @@ TEST(Via, then2) { ...@@ -212,8 +210,11 @@ TEST(Via, then2) {
} }
TEST(Via, then2Variadic) { TEST(Via, then2Variadic) {
struct Foo { void foo(Try<void>) {} }; struct Foo { bool a = false; void foo(Try<void>) { a = true; } };
Foo f; Foo f;
makeFuture().then(nullptr, &Foo::foo, &f); ManualExecutor x;
makeFuture().then(&x, &Foo::foo, &f);
EXPECT_FALSE(f.a);
x.run();
EXPECT_TRUE(f.a);
} }
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment