37auto when_all(std::vector<std::future<T>>& futures) -> std::vector<T>
39 std::vector<T> results;
40 results.reserve(futures.size());
41 std::exception_ptr first_error;
43 for (
auto& f : futures)
47 results.push_back(f.get());
52 first_error = std::current_exception();
57 std::rethrow_exception(first_error);
67inline void when_all(std::vector<std::future<void>>& futures)
69 std::exception_ptr first_error;
71 for (
auto& f : futures)
80 first_error = std::current_exception();
85 std::rethrow_exception(first_error);
97auto when_all_settled(std::vector<std::future<T>>& futures) -> std::vector<expected<T, std::exception_ptr>>
99 std::vector<expected<T, std::exception_ptr>> results;
100 results.reserve(futures.size());
102 for (
auto& f : futures)
106 results.push_back(f.get());
110 results.push_back(
unexpected(std::current_exception()));
120inline auto when_all_settled(std::vector<std::future<void>>& futures) -> std::vector<expected<void, std::exception_ptr>>
122 std::vector<expected<void, std::exception_ptr>> results;
123 results.reserve(futures.size());
125 for (
auto& f : futures)
130 results.emplace_back();
134 results.push_back(
unexpected(std::current_exception()));
154auto when_any(std::vector<std::future<T>>& futures) -> std::pair<size_t, T>
157 throw std::invalid_argument(
"when_any: empty futures vector");
159 thread_local std::mt19937 rng{std::random_device{}()};
160 std::uniform_int_distribution<size_t> dist(0, futures.size() - 1);
161 size_t const start = dist(rng);
162 unsigned backoff_ms = 1;
166 for (
size_t k = 0; k < futures.size(); ++k)
168 size_t const i = (start + k) % futures.size();
169 if (futures[i].wait_for(std::chrono::milliseconds(1)) == std::future_status::ready)
170 return {i, futures[i].get()};
172 std::this_thread::sleep_for(std::chrono::milliseconds(backoff_ms));
184inline auto when_any(std::vector<std::future<void>>& futures) ->
size_t
187 throw std::invalid_argument(
"when_any: empty futures vector");
189 thread_local std::mt19937 rng{std::random_device{}()};
190 std::uniform_int_distribution<size_t> dist(0, futures.size() - 1);
191 size_t const start = dist(rng);
192 unsigned backoff_ms = 1;
196 for (
size_t k = 0; k < futures.size(); ++k)
198 size_t const i = (start + k) % futures.size();
199 if (futures[i].wait_for(std::chrono::milliseconds(1)) == std::future_status::ready)
205 std::this_thread::sleep_for(std::chrono::milliseconds(backoff_ms));
Exception thrown by expected::value() when the object is in the error state.
Polyfill for std::expected (C++23) for pre-C++23 compilers.
auto when_all(std::vector< std::future< T > > &futures) -> std::vector< T >
Block until all futures complete, returning results in submission order.
auto when_all_settled(std::vector< std::future< T > > &futures) -> std::vector< expected< T, std::exception_ptr > >
Block until all futures complete, returning an expected per slot.
auto when_any(std::vector< std::future< T > > &futures) -> std::pair< size_t, T >
Block until the first future becomes ready.