userver: userver/engine/wait_any.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
wait_any.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/wait_any.hpp
4/// @brief Provides engine::WaitAny, engine::WaitAnyFor and engine::WaitAnyUntil
5
6#include <chrono>
7#include <optional>
8#include <vector>
9
10#include <userver/engine/deadline.hpp>
11#include <userver/utils/impl/span.hpp>
12#include <userver/utils/meta.hpp>
13
14USERVER_NAMESPACE_BEGIN
15
16namespace engine {
17
18/// @ingroup userver_concurrency
19///
20/// @brief Waits for the completion of any of the specified tasks or the
21/// cancellation of the caller.
22///
23/// Could be used to get the ready HTTP requests ASAP:
24/// @snippet src/clients/http/client_wait_test.cpp HTTP Client - waitany
25///
26/// Works with different types of tasks and futures:
27/// @snippet src/engine/wait_any_test.cpp sample waitany
28///
29/// @param tasks either a single container, or a pack of future-like elements.
30/// @returns the index of the completed task, or `std::nullopt` if there are no
31/// completed tasks (possible if current task was cancelled).
32template <typename... Tasks>
33std::optional<std::size_t> WaitAny(Tasks&... tasks);
34
35/// @ingroup userver_concurrency
36///
37/// @overload std::optional<std::size_t> WaitAny(Tasks&... tasks)
38template <typename... Tasks, typename Rep, typename Period>
39std::optional<std::size_t> WaitAnyFor(
40 const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks);
41
42/// @ingroup userver_concurrency
43///
44/// @overload std::optional<std::size_t> WaitAny(Tasks&... tasks)
45template <typename... Tasks, typename Clock, typename Duration>
46std::optional<std::size_t> WaitAnyUntil(
47 const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks);
48
49/// @ingroup userver_concurrency
50///
51/// @overload std::optional<std::size_t> WaitAny(Tasks&... tasks)
52template <typename... Tasks>
53std::optional<std::size_t> WaitAnyUntil(Deadline, Tasks&... tasks);
54
55template <typename... Tasks>
56std::optional<std::size_t> WaitAny(Tasks&... tasks) {
57 return engine::WaitAnyUntil(Deadline{}, tasks...);
58}
59
60template <typename... Tasks, typename Rep, typename Period>
61std::optional<std::size_t> WaitAnyFor(
62 const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks) {
63 return engine::WaitAnyUntil(Deadline::FromDuration(duration), tasks...);
64}
65
66template <typename... Tasks, typename Clock, typename Duration>
67std::optional<std::size_t> WaitAnyUntil(
68 const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks) {
69 return engine::WaitAnyUntil(Deadline::FromTimePoint(until), tasks...);
70}
71
72namespace impl {
73
74class ContextAccessor;
75
76std::optional<std::size_t> DoWaitAny(
77 utils::impl::Span<ContextAccessor*> targets, Deadline deadline);
78
79template <typename Container>
80std::optional<std::size_t> WaitAnyFromContainer(Deadline deadline,
81 Container& tasks) {
82 const auto size = std::size(tasks);
83 std::vector<ContextAccessor*> targets;
84 targets.reserve(size);
85
86 for (auto& task : tasks) {
87 targets.push_back(task.TryGetContextAccessor());
88 }
89
90 return DoWaitAny(targets, deadline);
91}
92
93template <typename... Tasks>
94std::optional<std::size_t> WaitAnyFromTasks(Deadline deadline,
95 Tasks&... tasks) {
96 ContextAccessor* wa_elements[]{tasks.TryGetContextAccessor()...};
97 return DoWaitAny(wa_elements, deadline);
98}
99
100inline std::optional<std::size_t> WaitAnyFromTasks(Deadline) { return {}; }
101
102} // namespace impl
103
104template <typename... Tasks>
105std::optional<std::size_t> WaitAnyUntil(Deadline deadline, Tasks&... tasks) {
106 if constexpr (meta::impl::IsSingleRange<Tasks...>()) {
107 return impl::WaitAnyFromContainer(deadline, tasks...);
108 } else {
109 return impl::WaitAnyFromTasks(deadline, tasks...);
110 }
111}
112
113} // namespace engine
114
115USERVER_NAMESPACE_END