userver: userver/engine/wait_any.hpp Source File
Loading...
Searching...
No Matches
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/meta.hpp>
12#include <userver/utils/span.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(const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks);
40
41/// @ingroup userver_concurrency
42///
43/// @overload std::optional<std::size_t> WaitAny(Tasks&... tasks)
44template <typename... Tasks, typename Clock, typename Duration>
45std::optional<std::size_t> WaitAnyUntil(const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks);
46
47/// @ingroup userver_concurrency
48///
49/// @overload std::optional<std::size_t> WaitAny(Tasks&... tasks)
50template <typename... Tasks>
51std::optional<std::size_t> WaitAnyUntil(Deadline, Tasks&... tasks);
52
53template <typename... Tasks>
54std::optional<std::size_t> WaitAny(Tasks&... tasks) {
55 return engine::WaitAnyUntil(Deadline{}, tasks...);
56}
57
58template <typename... Tasks, typename Rep, typename Period>
59std::optional<std::size_t> WaitAnyFor(const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks) {
60 return engine::WaitAnyUntil(Deadline::FromDuration(duration), tasks...);
61}
62
63template <typename... Tasks, typename Clock, typename Duration>
64std::optional<std::size_t> WaitAnyUntil(const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks) {
65 return engine::WaitAnyUntil(Deadline::FromTimePoint(until), tasks...);
66}
67
68namespace impl {
69
70class ContextAccessor;
71
72std::optional<std::size_t> DoWaitAny(utils::span<ContextAccessor*> targets, Deadline deadline);
73
74template <typename Container>
75std::optional<std::size_t> WaitAnyFromContainer(Deadline deadline, Container& tasks) {
76 const auto size = std::size(tasks);
77 std::vector<ContextAccessor*> targets;
78 targets.reserve(size);
79
80 for (auto& task : tasks) {
81 targets.push_back(task.TryGetContextAccessor());
82 }
83
84 return DoWaitAny(targets, deadline);
85}
86
87template <typename... Tasks>
88std::optional<std::size_t> WaitAnyFromTasks(Deadline deadline, Tasks&... tasks) {
89 ContextAccessor* wa_elements[]{tasks.TryGetContextAccessor()...};
90 return DoWaitAny(wa_elements, deadline);
91}
92
93inline std::optional<std::size_t> WaitAnyFromTasks(Deadline) { return {}; }
94
95} // namespace impl
96
97template <typename... Tasks>
98std::optional<std::size_t> WaitAnyUntil(Deadline deadline, Tasks&... tasks) {
99 if constexpr (meta::impl::IsSingleRange<Tasks...>()) {
100 return impl::WaitAnyFromContainer(deadline, tasks...);
101 } else {
102 return impl::WaitAnyFromTasks(deadline, tasks...);
103 }
104}
105
106} // namespace engine
107
108USERVER_NAMESPACE_END