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 "awaitable.hpp"
8#include "scoped_task.hpp"
9#include "../utility/utility.hpp"
10#include "../concurrency/concurrency.hpp"
11#include "../macros.hpp"
12#include <coroutine>
13#include <cstddef>
14#include <type_traits>
15#include <concepts>
16#include <variant>
17#include <tuple>
18#include <chrono>
19
20
21
22namespace hi::inline v1 {
23
35template<typename... Ts>
36class when_any {
37public:
38 using value_type = std::variant<variant_decay_t<await_resume_result_t<Ts>>...>;
39
51 when_any(awaitable auto&&...others) noexcept :
52 _awaiters(awaitable_cast<std::decay_t<decltype(others)>>{}(hi_forward(others))...)
53 {
54 }
55
56 ~when_any() {}
57
58 when_any(when_any&&) = delete;
59 when_any(when_any const&) = delete;
60 when_any& operator=(when_any&&) = delete;
61 when_any& operator=(when_any const&) = delete;
62
63 [[nodiscard]] constexpr bool await_ready() noexcept
64 {
65 static_assert(sizeof...(Ts) > 0);
66 return _await_ready<0>();
67 }
68
69 void await_suspend(std::coroutine_handle<> const& handle) noexcept
70 {
71 static_assert(sizeof...(Ts) > 0);
72 return _await_suspend<0>(handle);
73 }
74
75 value_type await_resume() noexcept
76 {
77 hi_assert(_value.has_value());
78 return *_value;
79 }
80
81private:
82 std::tuple<Ts...> _awaiters;
84 std::tuple<typename notifier<void(await_resume_result_t<Ts>)>::callback_token...> _task_cbts;
85 std::optional<value_type> _value;
86
87 template<awaitable_direct Awaiter>
88 static scoped_task<await_resume_result_t<Awaiter>> _await_suspend_task(Awaiter& awaiter)
89 {
90 co_return co_await awaiter;
91 }
92
93 template<std::size_t I>
94 void _destroy_tasks() noexcept
95 {
96 std::get<I>(_task_cbts) = {};
97 std::get<I>(_tasks) = {};
98 if constexpr (I + 1 < sizeof...(Ts)) {
99 _destroy_tasks<I + 1>();
100 }
101 }
102
103 template<std::size_t I>
104 bool _await_ready() noexcept
105 {
106 auto& task = std::get<I>(_tasks) = _await_suspend_task(std::get<I>(_awaiters));
107
108 if (task.done()) {
109 using arg_type = await_resume_result_t<decltype(std::get<I>(_awaiters))>;
110
111 if constexpr (std::is_same_v<arg_type, void>) {
112 _value = value_type{std::in_place_index<I>, std::monostate{}};
113 } else {
114 _value = value_type{std::in_place_index<I>, task.value()};
115 }
116 _destroy_tasks<0>();
117 return true;
118
119 } else if constexpr (I + 1 < sizeof...(Ts)) {
120 return _await_ready<I + 1>();
121
122 } else {
123 return false;
124 }
125 }
126
127 template<std::size_t I>
128 void _await_suspend(std::coroutine_handle<> const& handle) noexcept
129 {
130 using arg_type = await_resume_result_t<decltype(std::get<I>(_awaiters))>;
131
132 if constexpr (std::is_same_v<arg_type, void>) {
133 std::get<I>(_task_cbts) = std::get<I>(_tasks).subscribe(
134 [this, handle]() {
135 this->_value = value_type{std::in_place_index<I>, std::monostate{}};
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 this->_destroy_tasks<0>();
146 handle.resume();
147 },
148 callback_flags::main | callback_flags::once);
149 }
150
151 if constexpr (I + 1 < sizeof...(Ts)) {
152 _await_suspend<I + 1>(handle);
153 }
154 }
155
156 template<typename... Args>
157 friend class when_any;
158};
159
160template<awaitable... Others>
162
163} // namespace hi::inline v1
DOXYGEN BUG.
Definition algorithm.hpp:16
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
A functor for casting a type to an awaitable.
Definition awaitable.hpp:60
An awaitable that waits for any of the given awaitables to complete.
Definition when_any.hpp:36
when_any(awaitable auto &&...others) noexcept
Construct a when_any object from the given awaitables.
Definition when_any.hpp:51
Check if the type can be co_awaited on after conversion with awaitable_cast.
Definition awaitable.hpp:122