});
}
-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;
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;
/// 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.
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);
}
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;