userver: userver/engine/get_all.hpp Source File
Loading...
Searching...
No Matches
get_all.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/get_all.hpp
4/// @brief Provides engine::GetAll
5
6#include <type_traits>
7#include <vector>
8
9#include <userver/engine/wait_all_checked.hpp>
10#include <userver/utils/meta.hpp>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace engine {
15
16/// @ingroup userver_concurrency
17///
18/// @brief Waits for the successful completion of all of the specified tasks
19/// or the cancellation of the caller.
20///
21/// Effectively performs `for (auto& task : tasks) task.Get();` with a twist:
22/// task.Get() is called in tasks completion order rather than in provided
23/// order, thus exceptions are rethrown ASAP.
24///
25/// After successful return from this method the tasks are invalid,
26/// in case of an exception being thrown some of the tasks might be invalid.
27///
28/// @param tasks either a single container, or a pack of future-like elements.
29/// @returns `std::vector<Result>` or `void`, depending on the tasks result type
30/// (which must be the same for all `tasks`).
31/// @throws WaitInterruptedException when `current_task::IsCancelRequested()`
32/// and no TaskCancellationBlockers are present.
33/// @throws std::exception rethrows one of specified tasks exception, if any, in
34/// no particular order.
35///
36/// @note Has overall computational complexity of O(N^2),
37/// where N is the number of tasks.
38/// @note Prefer engine::WaitAllChecked for tasks with a result, unless you
39/// specifically need the results stored in a `std::vector` or when storing the
40/// results long-term.
41template <typename... Tasks>
42auto GetAll(Tasks&... tasks);
43
44namespace impl {
45
46template <typename Container>
47auto GetAllResultsFromContainer(Container& tasks) {
48 using Result = decltype(std::begin(tasks)->Get());
49
50 if constexpr (std::is_void_v<Result>) {
51 for (auto& task : tasks) {
52 task.Get();
53 }
54 return;
55 } else {
56 std::vector<Result> results;
57 results.reserve(std::size(tasks));
58 for (auto& task : tasks) {
59 results.push_back(task.Get());
60 }
61 return results;
62 }
63}
64
65template <typename... Tasks>
66auto GetAllResultsFromTasks(Tasks&... tasks) {
67 using Result = decltype((void(), ..., tasks.Get()));
68
69 if constexpr (std::is_void_v<Result>) {
70 static_assert((true && ... && std::is_void_v<decltype(tasks.Get())>));
71 (tasks.Get(), ...);
72 return;
73 } else {
74 std::vector<Result> results;
75 results.reserve(sizeof...(tasks));
76 (results.push_back(tasks.Get()), ...);
77 return results;
78 }
79}
80
81} // namespace impl
82
83template <typename... Tasks>
84auto GetAll(Tasks&... tasks) {
85 engine::WaitAllChecked(tasks...);
86 if constexpr (meta::impl::IsSingleRange<Tasks...>()) {
87 return impl::GetAllResultsFromContainer(tasks...);
88 } else {
89 return impl::GetAllResultsFromTasks(tasks...);
90 }
91}
92
93} // namespace engine
94
95USERVER_NAMESPACE_END