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 "utility.hpp"
8#include "scoped_task.hpp"
9#include "notifier.hpp"
10#include "awaitable.hpp"
11#include "awaitable_timer.hpp"
12#include <coroutine>
13#include <cstddef>
14#include <type_traits>
15#include <concepts>
16#include <variant>
17#include <tuple>
18#include <chrono>
19
20namespace hi::inline v1 {
21
33template<typename... Ts>
34class when_any {
35public:
36 using value_type = std::variant<variant_decay_t<await_resume_result_t<Ts>>...>;
37
49 when_any(awaitable auto&&...others) noexcept :
50 _awaiters(awaitable_cast<std::decay_t<decltype(others)>>{}(hi_forward(others))...)
51 {
52 }
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;
82 std::tuple<typename notifier<void(await_resume_result_t<Ts>)>::callback_token...> _task_cbts;
83 std::optional<value_type> _value;
84
85 template<awaitable_direct 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 this->_destroy_tasks<0>();
135 handle.resume();
136 },
137 callback_flags::main | callback_flags::once);
138
139 } else {
140 std::get<I>(_task_cbts) = std::get<I>(_tasks).subscribe(
141 [this, handle](arg_type const& arg) {
142 this->_value = value_type{std::in_place_index<I>, arg};
143 this->_destroy_tasks<0>();
144 handle.resume();
145 },
146 callback_flags::main | callback_flags::once);
147 }
148
149 if constexpr (I + 1 < sizeof...(Ts)) {
150 _await_suspend<I + 1>(handle);
151 }
152 }
153
154 template<typename... Args>
155 friend class when_any;
156};
157
158template<awaitable... Others>
159when_any(Others&&...) -> when_any<awaitable_cast_t<std::decay_t<Others>>...>;
160
161} // namespace hi::inline v1
#define hi_assert(expression,...)
Assert if expression is true.
Definition assert.hpp:87
Utilities used by the HikoGUI library itself.
#define hi_forward(x)
Forward a value, based on the decltype of the value.
Definition utility.hpp:29
DOXYGEN BUG.
Definition algorithm.hpp:15
A functor for casting a type to an awaitable.
Definition awaitable.hpp:58
An awaitable that waits for any of the given awaitables to complete.
Definition when_any.hpp:34
when_any(awaitable auto &&...others) noexcept
Construct a when_any object from the given awaitables.
Definition when_any.hpp:49
Check if the type can be co_awaited on after conversion with awaitable_cast.
Definition awaitable.hpp:120