12#include <boost/smart_ptr/intrusive_ptr.hpp>
14#include <userver/engine/awaitable.hpp>
15#include <userver/engine/deadline.hpp>
16#include <userver/utils/expected.hpp>
17#include <userver/utils/fast_pimpl.hpp>
18#include <userver/utils/meta.hpp>
19#include <userver/utils/span.hpp>
21USERVER_NAMESPACE_BEGIN
40template <
typename... Tasks>
41std::optional<std::size_t>
WaitAny(Tasks&... tasks);
47template <
typename... Tasks,
typename Rep,
typename Period>
48std::optional<std::size_t> WaitAnyFor(
const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks);
54template <
typename... Tasks,
typename Clock,
typename Duration>
55std::optional<std::size_t> WaitAnyUntil(
const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks);
61template <
typename... Tasks>
62std::optional<std::size_t> WaitAnyUntil(Deadline, Tasks&... tasks);
64template <
typename... Tasks>
65std::optional<std::size_t>
WaitAny(Tasks&... tasks) {
66 return engine::WaitAnyUntil(Deadline
{}, tasks...);
69template <
typename... Tasks,
typename Rep,
typename Period>
70std::optional<std::size_t> WaitAnyFor(
const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks) {
71 return engine::WaitAnyUntil(Deadline::FromDuration(duration), tasks...);
74template <
typename... Tasks,
typename Clock,
typename Duration>
75std::optional<std::size_t> WaitAnyUntil(
const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks) {
76 return engine::WaitAnyUntil(Deadline::FromTimePoint(until), tasks...);
81std::optional<std::size_t> DoWaitAny(
utils::
span<AwaitableToken> target_tokens, 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<AwaitableToken> targets;
87 targets.reserve(size);
89 for (
auto& task : tasks) {
90 static_assert(engine::
Awaitable<
decltype(task)>,
"Tasks must be awaitable");
91 targets.push_back(task.GetAwaitableToken());
94 return DoWaitAny(targets, deadline);
97template <
typename... Tasks>
98std::optional<std::size_t> WaitAnyFromTasks(Deadline deadline, Tasks&... tasks) {
99 static_assert((
true && ... && engine::
Awaitable<Tasks>),
"Tasks must be awaitable");
100 AwaitableToken wa_elements[]{tasks.GetAwaitableToken()...};
101 return DoWaitAny(wa_elements, deadline);
104inline std::optional<std::size_t> WaitAnyFromTasks(Deadline) {
return {}; }
108template <
typename... Tasks>
109std::optional<std::size_t> WaitAnyUntil(Deadline deadline, Tasks&... tasks) {
110 if constexpr (meta::impl::IsSingleRange<Tasks...>) {
111 return impl::WaitAnyFromContainer(deadline, tasks...);
113 return impl::WaitAnyFromTasks(deadline, tasks...);
137 ~WaitAnyContext()
noexcept;
184 template <
typename Rep,
typename Period>
186 return WaitUntil(Deadline::FromDuration(duration));
190 template <
typename Clock,
typename Duration>
192 return WaitUntil(Deadline::FromTimePoint(until));
209 void AppendToken(engine::AwaitableToken awaitable);
211 void AppendToken(std::uint64_t id, engine::AwaitableToken awaitable);
213 boost::intrusive_ptr<Impl> impl_;
216void WaitAnyContext::Append(engine::Awaitable
auto& awaitable) { AppendToken(awaitable.GetAwaitableToken()); }
218void WaitAnyContext::Append(std::uint64_t id, engine::Awaitable
auto& awaitable) {
219 AppendToken(id, awaitable.GetAwaitableToken());
229template <
typename... Awaitables>
232 [[maybe_unused]]
const auto append_one = [&context](
auto& arg) {
233 if constexpr (meta::
IsRange<
decltype(arg)>) {
234 for (
auto& awaitable : arg) {
235 context.Append(awaitable);
241 (append_one(awaitables), ...);