HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
when_any.hpp
1// Copyright Take Vos 2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "task.hpp"
8#include "../utility/utility.hpp"
9#include "../concurrency/concurrency.hpp"
10#include "../macros.hpp"
11#include <coroutine>
12#include <cstddef>
13#include <type_traits>
14#include <concepts>
15#include <variant>
16#include <tuple>
17#include <chrono>
18
19hi_export_module(hikogui.dispatch : when_any);
20
21hi_export namespace hi::inline v1 {
22
23namespace detail {
24
36template<awaitable... Ts>
37class when_any {
38public:
39 using value_type = std::variant<variant_decay_t<await_resume_result_t<Ts>>...>;
40
52 when_any(Ts const&...args) noexcept : _awaiters(args...) {}
53
54 ~when_any() {}
55
56 when_any(when_any&&) = delete;
57 when_any(when_any const&) = delete;
58 when_any& operator=(when_any&&) = delete;
59 when_any& operator=(when_any const&) = delete;
60
61 [[nodiscard]] constexpr bool await_ready() noexcept
62 {
63 static_assert(sizeof...(Ts) > 0);
64 return _await_ready<0>();
65 }
66
67 void await_suspend(std::coroutine_handle<> const& handle) noexcept
68 {
69 static_assert(sizeof...(Ts) > 0);
70 return _await_suspend<0>(handle);
71 }
72
73 value_type await_resume() noexcept
74 {
75 hi_assert(_value.has_value());
76 return *_value;
77 }
78
79private:
80 std::tuple<Ts...> _awaiters;
83 std::optional<value_type> _value;
84
85 template<awaitable Awaiter>
86 static scoped_task<await_resume_result_t<Awaiter>> _await_suspend_task(Awaiter& awaiter)
87 {
88 co_return co_await awaiter;
89 }
90
91 template<std::size_t I>
92 void _destroy_tasks() noexcept
93 {
94 std::get<I>(_task_cbts) = {};
95 std::get<I>(_tasks) = {};
96 if constexpr (I + 1 < sizeof...(Ts)) {
97 _destroy_tasks<I + 1>();
98 }
99 }
100
101 template<std::size_t I>
102 bool _await_ready() noexcept
103 {
104 auto& task = std::get<I>(_tasks) = _await_suspend_task(std::get<I>(_awaiters));
105
106 if (task.done()) {
107 using arg_type = await_resume_result_t<decltype(std::get<I>(_awaiters))>;
108
109 if constexpr (std::is_same_v<arg_type, void>) {
110 _value = value_type{std::in_place_index<I>, std::monostate{}};
111 } else {
112 _value = value_type{std::in_place_index<I>, task.value()};
113 }
114 _destroy_tasks<0>();
115 return true;
116
117 } else if constexpr (I + 1 < sizeof...(Ts)) {
118 return _await_ready<I + 1>();
119
120 } else {
121 return false;
122 }
123 }
124
125 template<std::size_t I>
126 void _await_suspend(std::coroutine_handle<> const& handle) noexcept
127 {
128 using arg_type = await_resume_result_t<decltype(std::get<I>(_awaiters))>;
129
130 if constexpr (std::is_same_v<arg_type, void>) {
131 std::get<I>(_task_cbts) = std::get<I>(_tasks).subscribe(
132 [this, handle]() {
133 this->_value = value_type{std::in_place_index<I>, std::monostate{}};
134
135 // Unsubscribe all the other tasks and callbacks.
136 this->_destroy_tasks<0>();
137 handle.resume();
138 },
139 callback_flags::main | callback_flags::once);
140
141 } else {
142 std::get<I>(_task_cbts) = std::get<I>(_tasks).subscribe(
143 [this, handle](arg_type const& arg) {
144 this->_value = value_type{std::in_place_index<I>, arg};
145
146 // Unsubscribe all the other tasks and callbacks.
147 this->_destroy_tasks<0>();
148 handle.resume();
149 },
150 callback_flags::main | callback_flags::once);
151 }
152
153 if constexpr (I + 1 < sizeof...(Ts)) {
154 _await_suspend<I + 1>(handle);
155 }
156 }
157};
158
159} // namespace detail
160
172template<convertible_to_awaitable... Args>
173auto when_any(Args const&...args)
174{
175 return detail::when_any(awaitable_cast<std::remove_cvref_t<Args>>{}(args)...);
176}
177
178} // namespace hi::inline v1
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
auto when_any(Args const &...args)
await on a set of objects which can be converted to an awaitable.
Definition when_any.hpp:173
Definition awaitable.hpp:41
An awaitable that waits for any of the given awaitables to complete.
Definition when_any.hpp:37
when_any(Ts const &...args) noexcept
Construct a when_any object from the given awaitables.
Definition when_any.hpp:52