@@ -83,11 +83,15 @@ struct IsFuture<Future<T>> : std::true_type {};
8383
8484// Returns a `Future` that will be successful if all `futures` complete
8585// successfully, or return a first encountered error.
86+ //
87+ // If any of the futures is invalid, the returned future will be invalid.
8688Future<> JoinFutures (absl::Span<const Future<>> futures);
8789
8890// Returns a `Future` that will be successful if all `futures` complete
8991// successfully, or return a first encountered error. Copies values from
9092// completed futures into the result vector.
93+ //
94+ // If any of the futures is invalid, the returned future will be invalid.
9195template <typename T, std::enable_if_t <!std::is_void_v<T>>* = nullptr >
9296Future<std::vector<T>> JoinFutures (absl::Span<const Future<T>> futures);
9397
@@ -96,6 +100,8 @@ Future<std::vector<T>> JoinFutures(absl::Span<const Future<T>> futures);
96100// completed futures into the result vector and leaves `futures` in move-from
97101// state (for copyable `T` it still incurs a copy overhead, see `OnReady`
98102// documentation for details).
103+ //
104+ // If any of the futures is invalid, the returned future will be invalid.
99105template <typename T, std::enable_if_t <!std::is_void_v<T>>* = nullptr >
100106Future<std::vector<T>> JoinFutures (absl::Span<Future<T>> futures);
101107
@@ -124,6 +130,8 @@ Future<std::vector<T>> JoinFutures(absl::Span<Future<T>> futures);
124130// If custom result type for `JoinFutures` is not defined (is void by default),
125131// then the result type will be inferred as `std::tuple`. Otherwise the result
126132// value of type `R` will be constructed from expanded tuple values.
133+ //
134+ // If any of the futures is invalid, the returned future will be invalid.
127135template <typename R = void , typename ... Futures,
128136 std::enable_if_t <std::conjunction_v<
129137 internal::IsFuture<std::decay_t <Futures>>...>>* = nullptr >
@@ -1581,6 +1589,9 @@ Future<std::vector<T>> JoinFutures(absl::Span<const Future<T>> futures) {
15811589 std::move (promise));
15821590
15831591 for (size_t index = 0 ; index < futures.size (); ++index) {
1592+ if (!futures[index].IsValid ()) [[unlikely]] {
1593+ return {};
1594+ }
15841595 futures[index].OnReady ([index, join](absl::StatusOr<T> value) {
15851596 join->OnReady (index, std::move (value));
15861597 });
@@ -1602,6 +1613,9 @@ Future<std::vector<T>> JoinFutures(absl::Span<Future<T>> futures) {
16021613 std::move (promise));
16031614
16041615 for (size_t index = 0 ; index < futures.size (); ++index) {
1616+ if (!futures[index].IsValid ()) [[unlikely]] {
1617+ return {};
1618+ }
16051619 std::move (futures[index]).OnReady ([index, join](absl::StatusOr<T> value) {
16061620 join->OnReady (index, std::move (value));
16071621 });
@@ -1729,6 +1743,10 @@ auto JoinFutures(Futures&&... futures) {
17291743 auto join = std::make_shared<internal::JoinStatic<PromiseResult, State>>(
17301744 sizeof ...(futures), std::move (promise));
17311745
1746+ if (((!futures.IsValid ()) || ...)) [[unlikely]] {
1747+ return tsl::Future<PromiseResult>();
1748+ }
1749+
17321750 using Is = std::make_index_sequence<sizeof ...(Futures)>;
17331751 join->OnReady (std::move (join), Is{}, std::forward<Futures>(futures)...);
17341752
0 commit comments