Commit 4d3071a3 authored by Lee Howes's avatar Lee Howes Committed by Facebook Github Bot

Executor-taking and SemiFuture versions of folly::futures::map.

Summary: Allow map to take a SemiFuture vector by changing the way the return type is deduced. Add overloads that take executor to apply.via and run the mapped tasks on a specified executor, and additionally return a Future that completes on that executor.

Reviewed By: andriigrynenko

Differential Revision: D7559540

fbshipit-source-id: f9480ea89fcfaa25a050ee7428dc69de300ccfde
parent 41bb0dc1
......@@ -2306,6 +2306,16 @@ std::vector<Future<Result>> map(It first, It last, F func) {
}
return results;
}
template <class It, class F, class ItT, class Result>
std::vector<Future<Result>> map(Executor& exec, It first, It last, F func) {
std::vector<Future<Result>> results;
for (auto it = first; it != last; it++) {
results.push_back(std::move(*it).via(&exec).then(func));
}
return results;
}
} // namespace futures
template <class Clock>
......
......@@ -59,6 +59,21 @@ namespace futures {
std::declval<ItT>().then(std::declval<F>()))::value_type>
std::vector<Future<Result>> map(It first, It last, F func);
/**
* Set func as the callback for each input Future and return a vector of
* Futures containing the results in the input order and completing on
* exec.
*/
template <
class It,
class F,
class ItT = typename std::iterator_traits<It>::value_type,
class Result =
typename decltype(std::move(std::declval<ItT>())
.via(std::declval<Executor*>())
.then(std::declval<F>()))::value_type>
std::vector<Future<Result>> map(Executor& exec, It first, It last, F func);
// Sugar for the most common case
template <class Collection, class F>
auto map(Collection&& c, F&& func)
......@@ -66,6 +81,13 @@ namespace futures {
return map(c.begin(), c.end(), std::forward<F>(func));
}
// Sugar for the most common case
template <class Collection, class F>
auto map(Executor& exec, Collection&& c, F&& func)
-> decltype(map(exec, c.begin(), c.end(), func)) {
return map(exec, c.begin(), c.end(), std::forward<F>(func));
}
} // namespace futures
/**
......
......@@ -44,3 +44,55 @@ TEST(Map, basic) {
EXPECT_TRUE(collect(fs2).isReady());
}
TEST(Map, executor) {
Promise<int> p1;
Promise<int> p2;
Promise<int> p3;
folly::InlineExecutor exec;
std::vector<Future<int>> fs;
fs.push_back(p1.getFuture());
fs.push_back(p2.getFuture());
fs.push_back(p3.getFuture());
int c = 0;
std::vector<Future<Unit>> fs2 =
futures::map(exec, fs, [&](int i) { c += i; });
// Ensure we call the callbacks as the futures complete regardless of order
p2.setValue(1);
EXPECT_EQ(1, c);
p3.setValue(1);
EXPECT_EQ(2, c);
p1.setValue(1);
EXPECT_EQ(3, c);
EXPECT_TRUE(collect(fs2).isReady());
}
TEST(Map, semifuture) {
Promise<int> p1;
Promise<int> p2;
Promise<int> p3;
folly::InlineExecutor exec;
std::vector<SemiFuture<int>> fs;
fs.push_back(p1.getSemiFuture());
fs.push_back(p2.getSemiFuture());
fs.push_back(p3.getSemiFuture());
int c = 0;
std::vector<Future<Unit>> fs2 =
futures::map(exec, fs, [&](int i) { c += i; });
// Ensure we call the callbacks as the futures complete regardless of order
p2.setValue(1);
EXPECT_EQ(1, c);
p3.setValue(1);
EXPECT_EQ(2, c);
p1.setValue(1);
EXPECT_EQ(3, c);
EXPECT_TRUE(collect(fs2).isReady());
}
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