12#include <boost/smart_ptr/intrusive_ptr.hpp>
14#include <userver/engine/deadline.hpp>
15#include <userver/utils/fast_pimpl.hpp>
16#include <userver/utils/meta.hpp>
17#include <userver/utils/span.hpp>
19USERVER_NAMESPACE_BEGIN
38template <
typename... Tasks>
39std::optional<std::size_t>
WaitAny(Tasks&... tasks);
45template <
typename... Tasks,
typename Rep,
typename Period>
46std::optional<std::size_t> WaitAnyFor(
const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks);
52template <
typename... Tasks,
typename Clock,
typename Duration>
53std::optional<std::size_t> WaitAnyUntil(
const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks);
59template <
typename... Tasks>
60std::optional<std::size_t> WaitAnyUntil(Deadline, Tasks&... tasks);
62template <
typename... Tasks>
63std::optional<std::size_t>
WaitAny(Tasks&... tasks) {
64 return engine::WaitAnyUntil(Deadline
{}, tasks...);
67template <
typename... Tasks,
typename Rep,
typename Period>
68std::optional<std::size_t> WaitAnyFor(
const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks) {
69 return engine::WaitAnyUntil(Deadline::FromDuration(duration), tasks...);
72template <
typename... Tasks,
typename Clock,
typename Duration>
73std::optional<std::size_t> WaitAnyUntil(
const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks) {
74 return engine::WaitAnyUntil(Deadline::FromTimePoint(until), tasks...);
81std::optional<std::size_t> DoWaitAny(
utils::span<ContextAccessor*> targets, Deadline deadline);
83template <
typename Container>
84std::optional<std::size_t> WaitAnyFromContainer(Deadline deadline, Container& tasks) {
85 const auto size = std::size(tasks);
86 std::vector<ContextAccessor*> targets;
87 targets.reserve(size);
89 for (
auto& task : tasks) {
90 targets.push_back(task.TryGetContextAccessor());
93 return DoWaitAny(targets, deadline);
96template <
typename... Tasks>
97std::optional<std::size_t> WaitAnyFromTasks(Deadline deadline, Tasks&... tasks) {
98 ContextAccessor* wa_elements[]{tasks.TryGetContextAccessor()...};
99 return DoWaitAny(wa_elements, deadline);
102inline std::optional<std::size_t> WaitAnyFromTasks(Deadline) {
return {}; }
106template <
typename... Tasks>
107std::optional<std::size_t> WaitAnyUntil(Deadline deadline, Tasks&... tasks) {
108 if constexpr (meta::impl::IsSingleRange<Tasks...>()) {
109 return impl::WaitAnyFromContainer(deadline, tasks...);
111 return impl::WaitAnyFromTasks(deadline, tasks...);
123class WaitAnyContext
final {
126 ~WaitAnyContext()
noexcept;
127 WaitAnyContext(WaitAnyContext&&)
noexcept;
128 WaitAnyContext& operator=(WaitAnyContext&& other)
noexcept;
129 WaitAnyContext(
const WaitAnyContext&) =
delete;
130 WaitAnyContext& operator=(
const WaitAnyContext&) =
delete;
137 template <
typename... Awaitables>
138 void Append(Awaitables&... awaitables);
159 template <
typename Rep,
typename Period>
160 std::optional<std::
uint64_t>
WaitFor(
const std::chrono::duration<Rep, Period>& duration) {
161 return WaitUntil(Deadline::FromDuration(duration));
165 template <
typename Clock,
typename Duration>
166 std::optional<std::uint64_t> WaitUntil(
const std::chrono::time_point<Clock, Duration>& until) {
167 return WaitUntil(Deadline::FromTimePoint(until));
184 template <
typename Container>
185 void AppendFromContainer(Container& awaitables);
187 template <
typename Awaitable>
188 void AppendSingle(Awaitable& awaitable);
190 void AppendAccessor(
impl::ContextAccessor* awaitable);
192 boost::intrusive_ptr<Impl> impl_;
195template <
typename Container>
196void WaitAnyContext::AppendFromContainer(Container& awaitables) {
197 for (
auto& awaitable : awaitables) {
198 AppendAccessor(awaitable.TryGetContextAccessor());
202template <
typename Awaitable>
203void WaitAnyContext::AppendSingle(Awaitable& awaitable) {
204 if constexpr (meta::impl::IsSingleRange<Awaitable>()) {
205 AppendFromContainer(awaitable);
207 AppendAccessor(awaitable.TryGetContextAccessor());
211template <
typename... Awaitables>
212void WaitAnyContext::
Append(Awaitables&... awaitables) {
213 (AppendSingle(awaitables), ...);
223template <
typename... Awaitables>
225 auto context = WaitAnyContext();
226 if constexpr (
sizeof...(Awaitables) > 0) {
227 context.Append(awaitables...);