Commit 0593c224 authored by Hannes Roth's avatar Hannes Roth Committed by Viswanath Sivakumar

(Wangle) chain -> thenMulti + thenMultiWithExecutor

Summary:
If we make `chain` a member function we can avoid the type issues and infer everything. I also added thenMulti for symmetry. Sadly the compiler doesn't like having a thenMulti with an optional `Executor*` as the first argument, it fails after some deductions. Hence `thenMultiWithExecutor`.

itssobeautiful

Test Plan: Run all the tests.

Reviewed By: hans@fb.com

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

FB internal diff: D2021000

Signature: t1:2021000:1431557618:169447dc9d747b23a8a1ba830e78c43713d09a96
parent ad0c254d
main 2016.07.26 v2022.02.14.00 v2022.02.07.00 v2022.01.31.00 v2022.01.24.00 v2022.01.17.00 v2022.01.10.00 v2022.01.03.00 v2021.12.27.00 v2021.12.20.00 v2021.12.13.00 v2021.12.06.00 v2021.11.29.00 v2021.11.15.00 v2021.11.08.00 v2021.11.01.00 v2021.10.25.00 v2021.10.18.00 v2021.10.11.00 v2021.10.04.00 v2021.09.27.00 v2021.09.20.00 v2021.09.13.00 v2021.09.06.00 v2021.08.30.00 v2021.08.23.00 v2021.08.02.00 v2021.07.22.00 v2021.07.20.01 v2021.07.20.00 v2021.06.28.00 v2021.06.14.00 v2021.06.07.00 v2021.05.31.00 v2021.05.24.00 v2021.05.17.00 v2021.05.10.00 v2021.05.03.00 v2021.04.26.00 v2021.04.19.00 v2021.04.12.00 v2021.04.05.00 v2021.03.29.00 v2021.03.22.00 v2021.03.15.00 v2021.03.08.00 v2021.03.01.00 v2021.02.22.00 v2021.02.15.00 v2021.02.08.00 v2021.02.01.00 v2021.01.25.00 v2021.01.18.01 v2021.01.18.00 v2021.01.11.00 v2021.01.04.00 v2020.12.28.00 v2020.12.21.00 v2020.12.14.00 v2020.12.07.00 v2020.11.30.00 v2020.11.23.00 v2020.11.16.00 v2020.11.09.00 v2020.11.02.00 v2020.10.26.00 v2020.10.19.00 v2020.10.12.00 v2020.10.05.00 v2020.09.28.00 v2020.09.21.00 v2020.09.14.00 v2020.09.07.00 v2020.08.31.00 v2020.08.24.00 v2020.08.17.00 v2020.08.10.00 v2020.08.03.00 v2020.07.27.00 v2020.07.20.00 v2020.07.13.00 v2020.07.06.00 v2020.06.29.00 v2020.06.15.00 v2020.06.08.00 v2020.06.01.00 v2020.05.25.00 v2020.05.18.00 v2020.05.11.00 v2020.05.04.00 v2020.04.27.00 v2020.04.20.00 v2020.04.13.00 v2020.04.06.00 v2020.03.30.00 v2020.03.23.00 v2020.03.16.00 v2020.03.09.00 v2020.03.02.00 v2020.02.24.00 v2020.02.17.00 v2020.02.10.00 v2020.02.03.00 v2020.01.27.00 v2020.01.20.00 v2020.01.13.00 v2020.01.06.00 v2019.12.30.00 v2019.12.23.00 v2019.12.16.00 v2019.12.09.00 v2019.12.06.00 v2019.12.02.00 v2019.11.11.00 v2019.11.04.00 v2019.10.28.00 v2019.10.21.00 v2019.10.14.00 v2019.10.07.00 v2019.09.30.00 v2019.09.23.00 v2019.09.16.00 v2019.09.09.00 v2019.09.02.00 v2019.08.26.00 v2019.08.19.00 v2019.08.12.00 v2019.08.05.00 v2019.07.29.00 v2019.07.22.00 v2019.06.17.00 v2019.06.10.00 v2019.06.03.00 v2019.05.27.00 v2019.05.20.00 v2019.05.13.00 v2019.05.06.00 v2019.04.29.00 v2019.04.22.00 v2019.04.15.00 v2019.04.08.00 v2019.04.01.00 v2019.03.25.00 v2019.03.18.00 v2019.03.04.00 v2019.02.25.00 v2019.02.18.00 v2019.02.11.00 v2019.02.04.00 v2019.01.28.00 v2019.01.21.00 v2019.01.14.00 v2019.01.07.00 v2018.12.31.00 v2018.12.24.00 v2018.12.17.00 v2018.12.10.00 v2018.12.03.00 v2018.11.26.00 v2018.11.19.00 v2018.11.12.00 v2018.11.05.00 v2018.10.29.00 v2018.10.22.00 v2018.10.15.00 v2018.10.08.00 v2018.10.01.00 v2018.09.24.00 v2018.09.17.00 v2018.09.10.01 v2018.09.10.00 v2018.09.03.01 v2018.09.03.00 v2018.08.27.00 v2018.08.20.00 v2018.08.13.00 v2018.08.09.00 v2018.08.06.00 v2018.07.30.00 v2018.07.23.00 v2018.07.16.00 v2018.07.09.00 v2018.07.02.00 v2018.06.25.00 v2018.06.18.00 v2018.06.11.00 v2018.06.04.00 v2018.05.28.00 v2018.05.21.00 v2018.05.14.00 v2018.05.07.00 v2018.04.30.00 v2018.04.23.00 v2018.04.16.00 v2018.04.09.00 v2018.04.02.00 v2018.03.26.00 v2018.03.19.00 v2018.03.12.00 v2018.03.05.00 v2018.02.26.00 v2018.02.19.00 v2018.02.12.00 v2018.02.05.00 v2018.01.29.00 v2018.01.22.00 v2018.01.15.00 v2018.01.08.00 v2018.01.01.00 v2017.12.25.00 v2017.12.18.00 v2017.12.11.00 v2017.12.04.00 v2017.11.27.00 v2017.11.20.00 v2017.11.13.00 v2017.11.06.00 v2017.10.30.00 v2017.10.23.00 v2017.10.16.00 v2017.10.09.00 v2017.10.02.00 v2017.09.25.00 v2017.09.18.00 v2017.09.11.00 v2017.09.04.00 v2017.08.28.00 v2017.08.21.00 v2017.08.14.00 v2017.08.07.00 v2017.07.31.00 v2017.07.24.00 v2017.07.17.01 v2017.07.17.00 v2017.07.10.00 v2017.07.03.00 v2017.06.26.01 v2017.06.26.00 v2017.06.19.00 v2017.06.12.00 v2017.06.05.00 v2017.05.29.00 v2017.05.22.00 v2017.05.15.00 v2017.05.08.00 v2017.05.01.00 v2017.04.24.00 v2017.04.17.00 v2017.04.10.00 v2017.04.03.00 v2017.03.27.00 v2017.03.20.00 v2017.03.13.00 v2017.03.06.00 v2016.12.19.00 v2016.12.12.00 v2016.12.05.00 v2016.11.28.00 v2016.11.21.00 v2016.11.14.00 v2016.11.07.00 v2016.10.31.00 v2016.10.24.00 v2016.10.17.00 v2016.10.10.00 v2016.10.03.00 v2016.09.26.00 v2016.09.19.00 v2016.09.12.01 v2016.09.12.00 v2016.09.05.00 v2016.08.29.00 v2016.08.22.00 v2016.08.15.00 v2016.08.08.00 v2016.08.01.00 v2016.07.29.00 v0.57.0 v0.56.0 v0.55.0 v0.54.0 v0.53.0 v0.52.0 v0.51.0 v0.50.0 v0.49.1 v0.49.0 v0.48.0 v0.47.0 v0.45.0 v0.43.0 v0.42.0 v0.41.0 v0.40.0 v0.39.0 deprecate-dynamic-initializer
No related merge requests found
......@@ -1018,30 +1018,47 @@ Future<T> Future<T>::filter(F predicate) {
});
}
namespace futures {
namespace {
template <class Z>
Future<Z> chainHelper(Future<Z> f) {
return f;
}
template <class T>
template <class Callback>
auto Future<T>::thenMulti(Callback&& fn)
-> decltype(this->then(std::forward<Callback>(fn))) {
// thenMulti with one callback is just a then
return then(std::forward<Callback>(fn));
}
template <class Z, class F, class Fn, class... Callbacks>
Future<Z> chainHelper(F f, Fn fn, Callbacks... fns) {
return chainHelper<Z>(f.then(fn), fns...);
}
}
template <class T>
template <class Callback, class... Callbacks>
auto Future<T>::thenMulti(Callback&& fn, Callbacks&&... fns)
-> decltype(this->then(std::forward<Callback>(fn)).
thenMulti(std::forward<Callbacks>(fns)...)) {
// thenMulti with two callbacks is just then(a).thenMulti(b, ...)
return then(std::forward<Callback>(fn)).
thenMulti(std::forward<Callbacks>(fns)...);
}
template <class A, class Z, class... Callbacks>
std::function<Future<Z>(Try<A>)>
chain(Callbacks... fns) {
MoveWrapper<Promise<A>> pw;
MoveWrapper<Future<Z>> fw(chainHelper<Z>(pw->getFuture(), fns...));
return [=](Try<A> t) mutable {
pw->setTry(std::move(t));
return std::move(*fw);
};
}
template <class T>
template <class Callback, class... Callbacks>
auto Future<T>::thenMultiWithExecutor(Executor* x, Callback&& fn,
Callbacks&&... fns)
-> decltype(this->then(std::forward<Callback>(fn)).
thenMulti(std::forward<Callbacks>(fns)...)) {
// thenMultiExecutor with two callbacks is
// via(x).then(a).thenMulti(b, ...).via(oldX)
auto oldX = getExecutor();
setExecutor(x);
return then(std::forward<Callback>(fn)).
thenMulti(std::forward<Callbacks>(fns)...).via(oldX);
}
template <class T>
template <class Callback>
auto Future<T>::thenMultiWithExecutor(Executor* x, Callback&& fn)
-> decltype(this->then(std::forward<Callback>(fn))) {
// thenMulti with one callback is just a then with an executor
return then(x, std::forward<Callback>(fn));
}
namespace futures {
template <class It, class F, class ItT, class Result>
std::vector<Future<Result>> map(It first, It last, F func) {
std::vector<Future<Result>> results;
......
......@@ -380,6 +380,42 @@ class Future {
template <class I, class F>
Future<I> reduce(I&& initial, F&& func);
/// Create a Future chain from a sequence of callbacks. i.e.
///
/// f.then(a).then(b).then(c)
///
/// where f is a Future<A> and the result of the chain is a Future<D>
/// becomes
///
/// f.thenMulti(a, b, c);
template <class Callback, class... Callbacks>
auto thenMulti(Callback&& fn, Callbacks&&... fns)
-> decltype(this->then(std::forward<Callback>(fn)).
thenMulti(std::forward<Callbacks>(fns)...));
// Nothing to see here, just thenMulti's base case
template <class Callback>
auto thenMulti(Callback&& fn)
-> decltype(this->then(std::forward<Callback>(fn)));
/// Create a Future chain from a sequence of callbacks. i.e.
///
/// f.via(executor).then(a).then(b).then(c).via(oldExecutor)
///
/// where f is a Future<A> and the result of the chain is a Future<D>
/// becomes
///
/// f.thenMultiWithExecutor(executor, a, b, c);
template <class Callback, class... Callbacks>
auto thenMultiWithExecutor(Executor* x, Callback&& fn, Callbacks&&... fns)
-> decltype(this->then(std::forward<Callback>(fn)).
thenMulti(std::forward<Callbacks>(fns)...));
// Nothing to see here, just thenMultiWithExecutor's base case
template <class Callback>
auto thenMultiWithExecutor(Executor* x, Callback&& fn)
-> decltype(this->then(std::forward<Callback>(fn)));
protected:
typedef detail::Core<T>* corePtr;
......
......@@ -39,19 +39,6 @@ namespace futures {
/// Futures you will pay no Timekeeper thread overhead.
Future<void> sleep(Duration, Timekeeper* = nullptr);
/// Create a Future chain from a sequence of callbacks. i.e.
///
/// f.then(a).then(b).then(c);
///
/// where f is a Future<A> and the result of the chain is a Future<Z>
/// becomes
///
/// f.then(chain<A,Z>(a, b, c));
// If anyone figures how to get chain to deduce A and Z, I'll buy you a drink.
template <class A, class Z, class... Callbacks>
std::function<Future<Z>(Try<A>)>
chain(Callbacks... fns);
/**
* Set func as the callback for each input Future and return a vector of
* Futures containing the results in the input order.
......
......@@ -171,16 +171,16 @@ TEST_F(ViaFixture, viaAssignment) {
TEST(Via, chain1) {
EXPECT_EQ(42,
makeFuture()
.then(futures::chain<void, int>([] { return 42; }))
.thenMulti([] { return 42; })
.get());
}
TEST(Via, chain3) {
int count = 0;
auto f = makeFuture().then(futures::chain<void, int>(
auto f = makeFuture().thenMulti(
[&]{ count++; return 3.14159; },
[&](double) { count++; return std::string("hello"); },
[&]{ count++; return makeFuture(42); }));
[&]{ count++; return makeFuture(42); });
EXPECT_EQ(42, f.get());
EXPECT_EQ(3, count);
}
......@@ -228,6 +228,32 @@ TEST(Via, priority) {
EXPECT_EQ(3, exe.count2);
}
TEST_F(ViaFixture, chainX1) {
EXPECT_EQ(42,
makeFuture()
.thenMultiWithExecutor(eastExecutor.get(),[] { return 42; })
.get());
}
TEST_F(ViaFixture, chainX3) {
auto westThreadId = std::this_thread::get_id();
int count = 0;
auto f = via(westExecutor.get()).thenMultiWithExecutor(
eastExecutor.get(),
[&]{
EXPECT_NE(std::this_thread::get_id(), westThreadId);
count++; return 3.14159;
},
[&](double) { count++; return std::string("hello"); },
[&]{ count++; })
.then([&](){
EXPECT_EQ(std::this_thread::get_id(), westThreadId);
return makeFuture(42);
});
EXPECT_EQ(42, f.getVia(waiter.get()));
EXPECT_EQ(3, count);
}
TEST(Via, then2) {
ManualExecutor x1, x2;
bool a = false, b = false, c = false;
......
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