12#include <boost/smart_ptr/intrusive_ptr.hpp>
14#include <userver/engine/awaitable.hpp>
15#include <userver/engine/deadline.hpp>
16#include <userver/utils/fast_pimpl.hpp>
17#include <userver/utils/meta.hpp>
18#include <userver/utils/span.hpp>
20USERVER_NAMESPACE_BEGIN
39template <
typename... Tasks>
40std::optional<std::size_t>
WaitAny(Tasks&... tasks);
46template <
typename... Tasks,
typename Rep,
typename Period>
47std::optional<std::size_t> WaitAnyFor(
const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks);
53template <
typename... Tasks,
typename Clock,
typename Duration>
54std::optional<std::size_t> WaitAnyUntil(
const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks);
60template <
typename... Tasks>
61std::optional<std::size_t> WaitAnyUntil(Deadline, Tasks&... tasks);
63template <
typename... Tasks>
64std::optional<std::size_t>
WaitAny(Tasks&... tasks) {
65 return engine::WaitAnyUntil(Deadline
{}, tasks...);
68template <
typename... Tasks,
typename Rep,
typename Period>
69std::optional<std::size_t> WaitAnyFor(
const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks) {
70 return engine::WaitAnyUntil(Deadline::FromDuration(duration), tasks...);
73template <
typename... Tasks,
typename Clock,
typename Duration>
74std::optional<std::size_t> WaitAnyUntil(
const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks) {
75 return engine::WaitAnyUntil(Deadline::FromTimePoint(until), tasks...);
80std::optional<std::size_t> DoWaitAny(
utils::
span<AwaitableToken> target_tokens, Deadline deadline);
82template <
typename Container>
83std::optional<std::size_t> WaitAnyFromContainer(Deadline deadline, Container& tasks) {
84 const auto size = std::size(tasks);
85 std::vector<AwaitableToken> targets;
86 targets.reserve(size);
88 for (
auto& task : tasks) {
89 static_assert(engine::Awaitable<
decltype(task)>,
"Tasks must be awaitable");
90 targets.push_back(task.GetAwaitableToken());
93 return DoWaitAny(targets, deadline);
96template <
typename... Tasks>
97std::optional<std::size_t> WaitAnyFromTasks(Deadline deadline, Tasks&... tasks) {
98 static_assert((
true && ... && engine::Awaitable<Tasks>),
"Tasks must be awaitable");
99 AwaitableToken wa_elements[]{tasks.GetAwaitableToken()...};
100 return DoWaitAny(wa_elements, deadline);
103inline std::optional<std::size_t> WaitAnyFromTasks(Deadline) {
return {}; }
107template <
typename... Tasks>
108std::optional<std::size_t> WaitAnyUntil(Deadline deadline, Tasks&... tasks) {
109 if constexpr (meta::impl::IsSingleRange<Tasks...>) {
110 return impl::WaitAnyFromContainer(deadline, tasks...);
112 return impl::WaitAnyFromTasks(deadline, tasks...);
127 ~WaitAnyContext()
noexcept;
173 template <
typename Rep,
typename Period>
174 std::optional<std::
uint64_t>
WaitFor(
const std::chrono::duration<Rep, Period>& duration) {
175 return WaitUntil(Deadline::FromDuration(duration));
179 template <
typename Clock,
typename Duration>
180 std::optional<std::uint64_t> WaitUntil(
const std::chrono::time_point<Clock, Duration>& until) {
181 return WaitUntil(Deadline::FromTimePoint(until));
198 void AppendToken(engine::AwaitableToken awaitable);
200 void AppendToken(std::uint64_t id, engine::AwaitableToken awaitable);
202 boost::intrusive_ptr<Impl> impl_;
205void WaitAnyContext::Append(engine::Awaitable
auto& awaitable) { AppendToken(awaitable.GetAwaitableToken()); }
207void WaitAnyContext::Append(std::uint64_t id, engine::Awaitable
auto& awaitable) {
208 AppendToken(id, awaitable.GetAwaitableToken());
218template <
typename... Awaitables>
221 [[maybe_unused]]
const auto append_one = [&context](
auto& arg) {
222 if constexpr (meta::IsRange<
decltype(arg)>) {
223 for (
auto& awaitable : arg) {
224 context.Append(awaitable);
230 (append_one(awaitables), ...);