return ctx->p.getFuture();
}
+// collectAnyWithoutException (iterator)
+
+template <class InputIterator>
+Future<std::pair<
+ size_t,
+ typename std::iterator_traits<InputIterator>::value_type::value_type>>
+collectAnyWithoutException(InputIterator first, InputIterator last) {
+ typedef
+ typename std::iterator_traits<InputIterator>::value_type::value_type T;
+
+ struct CollectAnyWithoutExceptionContext {
+ CollectAnyWithoutExceptionContext(){};
+ Promise<std::pair<size_t, T>> p;
+ std::atomic<bool> done{false};
+ std::atomic<size_t> nFulfilled{0};
+ size_t nTotal;
+ };
+
+ auto ctx = std::make_shared<CollectAnyWithoutExceptionContext>();
+ ctx->nTotal = std::distance(first, last);
+
+ mapSetCallback<T>(first, last, [ctx](size_t i, Try<T>&& t) {
+ if (!t.hasException() && !ctx->done.exchange(true)) {
+ ctx->p.setValue(std::make_pair(i, std::move(t.value())));
+ } else if (++ctx->nFulfilled == ctx->nTotal) {
+ ctx->p.setException(t.exception());
+ }
+ });
+ return ctx->p.getFuture();
+}
+
// collectN (iterator)
template <class InputIterator>
return collectAny(c.begin(), c.end());
}
+/** Similar to collectAny, collectAnyWithoutException return the first Future to
+ * complete without exceptions. If none of the future complete without
+ * excpetions, the last exception will be returned as a result.
+ */
+template <class InputIterator>
+Future<std::pair<
+ size_t,
+ typename std::iterator_traits<InputIterator>::value_type::value_type>>
+collectAnyWithoutException(InputIterator first, InputIterator last);
+
+/// Sugar for the most common case
+template <class Collection>
+auto collectAnyWithoutException(Collection&& c)
+ -> decltype(collectAnyWithoutException(c.begin(), c.end())) {
+ return collectAnyWithoutException(c.begin(), c.end());
+}
+
/** when n Futures have completed, the Future completes with a vector of
the index and Try of those n Futures (the indices refer to the original
order, but the result vector will be in an arbitrary order)
}
}
+TEST(Collect, collectAnyWithoutException) {
+ {
+ std::vector<Promise<int>> promises(10);
+ std::vector<Future<int>> futures;
+
+ for (auto& p : promises) {
+ futures.push_back(p.getFuture());
+ }
+
+ auto onef = collectAnyWithoutException(futures);
+
+ /* futures were moved in, so these are invalid now */
+ EXPECT_FALSE(onef.isReady());
+
+ promises[7].setValue(42);
+ EXPECT_TRUE(onef.isReady());
+ auto& idx_fut = onef.value();
+ EXPECT_EQ(7, idx_fut.first);
+ EXPECT_EQ(42, idx_fut.second);
+ }
+
+ // some exception before ready
+ {
+ std::vector<Promise<int>> promises(10);
+ std::vector<Future<int>> futures;
+
+ for (auto& p : promises) {
+ futures.push_back(p.getFuture());
+ }
+
+ auto onef = collectAnyWithoutException(futures);
+
+ EXPECT_FALSE(onef.isReady());
+
+ promises[3].setException(eggs);
+ EXPECT_FALSE(onef.isReady());
+ promises[4].setException(eggs);
+ EXPECT_FALSE(onef.isReady());
+ promises[0].setValue(99);
+ EXPECT_TRUE(onef.isReady());
+ auto& idx_fut = onef.value();
+ EXPECT_EQ(0, idx_fut.first);
+ EXPECT_EQ(99, idx_fut.second);
+ }
+
+ // all exceptions
+ {
+ std::vector<Promise<int>> promises(10);
+ std::vector<Future<int>> futures;
+
+ for (auto& p : promises) {
+ futures.push_back(p.getFuture());
+ }
+
+ auto onef = collectAnyWithoutException(futures);
+
+ EXPECT_FALSE(onef.isReady());
+ for (int i = 0; i < 9; ++i) {
+ promises[i].setException(eggs);
+ }
+ EXPECT_FALSE(onef.isReady());
+
+ promises[9].setException(eggs);
+ EXPECT_TRUE(onef.isReady());
+ EXPECT_TRUE(onef.hasException());
+ }
+}
TEST(Collect, alreadyCompleted) {
{