userver: userver/engine/get_all.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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