11#include <boost/smart_ptr/intrusive_ptr.hpp>
13#include <userver/engine/deadline.hpp>
14#include <userver/utils/fast_pimpl.hpp>
15#include <userver/utils/meta.hpp>
16#include <userver/utils/span.hpp>
18USERVER_NAMESPACE_BEGIN
37template <
typename... Tasks>
38std::optional<std::size_t>
WaitAny(Tasks&... tasks);
44template <
typename... Tasks,
typename Rep,
typename Period>
45std::optional<std::size_t> WaitAnyFor(
const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks);
51template <
typename... Tasks,
typename Clock,
typename Duration>
52std::optional<std::size_t> WaitAnyUntil(
const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks);
58template <
typename... Tasks>
59std::optional<std::size_t> WaitAnyUntil(Deadline, Tasks&... tasks);
61template <
typename... Tasks>
62std::optional<std::size_t>
WaitAny(Tasks&... tasks) {
63 return engine::WaitAnyUntil(Deadline
{}, tasks...);
66template <
typename... Tasks,
typename Rep,
typename Period>
67std::optional<std::size_t> WaitAnyFor(
const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks) {
68 return engine::WaitAnyUntil(Deadline::FromDuration(duration), tasks...);
71template <
typename... Tasks,
typename Clock,
typename Duration>
72std::optional<std::size_t> WaitAnyUntil(
const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks) {
73 return engine::WaitAnyUntil(Deadline::FromTimePoint(until), tasks...);
80std::optional<std::size_t> DoWaitAny(
utils::span<ContextAccessor*> targets, 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<ContextAccessor*> targets;
86 targets.reserve(size);
88 for (
auto& task : tasks) {
89 targets.push_back(task.TryGetContextAccessor());
92 return DoWaitAny(targets, deadline);
95template <
typename... Tasks>
96std::optional<std::size_t> WaitAnyFromTasks(Deadline deadline, Tasks&... tasks) {
97 ContextAccessor* wa_elements[]{tasks.TryGetContextAccessor()...};
98 return DoWaitAny(wa_elements, deadline);
101inline std::optional<std::size_t> WaitAnyFromTasks(Deadline) {
return {}; }
105template <
typename... Tasks>
106std::optional<std::size_t> WaitAnyUntil(Deadline deadline, Tasks&... tasks) {
107 if constexpr (meta::impl::IsSingleRange<Tasks...>()) {
108 return impl::WaitAnyFromContainer(deadline, tasks...);
110 return impl::WaitAnyFromTasks(deadline, tasks...);
122class WaitAnyContext
final {
125 ~WaitAnyContext()
noexcept;
126 WaitAnyContext(WaitAnyContext&&)
noexcept;
127 WaitAnyContext& operator=(WaitAnyContext&& other)
noexcept;
128 WaitAnyContext(
const WaitAnyContext&) =
delete;
129 WaitAnyContext& operator=(
const WaitAnyContext&) =
delete;
136 template <
typename... Awaitables>
137 void Append(Awaitables&... awaitables);
147 std::optional<std::uint64_t> WaitUntil(Deadline deadline);
150 template <
typename Rep,
typename Period>
151 std::optional<std::uint64_t> WaitFor(
const std::chrono::duration<Rep, Period>& duration) {
152 return WaitUntil(Deadline::FromDuration(duration));
156 template <
typename Clock,
typename Duration>
157 std::optional<std::uint64_t> WaitUntil(
const std::chrono::time_point<Clock, Duration>& until) {
158 return WaitUntil(Deadline::FromTimePoint(until));
175 template <
typename Container>
176 void AppendFromContainer(Container& awaitables);
178 template <
typename Awaitable>
179 void AppendSingle(Awaitable& awaitable);
181 void AppendAccessor(
impl::ContextAccessor* awaitable);
183 boost::intrusive_ptr<Impl> impl_;
186template <
typename Container>
187void WaitAnyContext::AppendFromContainer(Container& awaitables) {
188 for (
auto& awaitable : awaitables) {
189 AppendAccessor(awaitable.TryGetContextAccessor());
193template <
typename Awaitable>
194void WaitAnyContext::AppendSingle(Awaitable& awaitable) {
195 if constexpr (meta::impl::IsSingleRange<Awaitable>()) {
196 AppendFromContainer(awaitable);
198 AppendAccessor(awaitable.TryGetContextAccessor());
202template <
typename... Awaitables>
203void WaitAnyContext::
Append(Awaitables&... awaitables) {
204 (AppendSingle(awaitables), ...);
214template <
typename... Awaitables>
216 auto context = WaitAnyContext();
217 if constexpr (
sizeof...(Awaitables) > 0) {
218 context.Append(awaitables...);