21#include "pw_async2/dispatcher.h"
27template <
typename... Pendables>
33template <
size_t I,
typename T>
35 static constexpr size_t kIndex = I;
39 template <
typename... Pendables>
42 explicit SelectResult(T&& val) : value(std::move(val)) {}
47 static constexpr size_t kIndex = std::numeric_limits<size_t>::max();
48 std::nullopt_t value = std::nullopt;
55template <
typename Is,
typename... Pendables>
58template <
size_t... Is,
typename... Pendables>
60 using type = std::variant<SelectResult<Is, PendOutputOf<Pendables>>...,
64template <
typename ResultVariant,
65 typename AllPendablesCompletedHandler,
66 typename ReadyHandlers,
68void VisitSelectResult(ResultVariant&& variant,
69 AllPendablesCompletedHandler&& all_completed,
70 ReadyHandlers&& ready_handlers,
71 std::index_sequence<Is...>) {
74 using ArgType = std::decay_t<
decltype(arg)>;
75 if constexpr (std::is_same_v<ArgType, AllPendablesCompleted>) {
76 std::invoke(std::forward<AllPendablesCompletedHandler>(all_completed),
79 std::invoke(std::get<ArgType::kIndex>(
80 std::forward<ReadyHandlers>(ready_handlers)),
81 std::move(arg.value));
84 std::forward<ResultVariant>(variant));
129template <
typename... Pendables>
132 static_assert(
sizeof...(Pendables) > 0,
133 "Cannot select over an empty set of pendables");
136 std::make_index_sequence<
sizeof...(Pendables)>,
142 : pendables_(std::move(pendables)...) {}
152 template <
size_t kTupleIndex>
154 if constexpr (kTupleIndex <
sizeof...(Pendables)) {
155 auto& pendable = std::get<kTupleIndex>(pendables_);
157 if (pendable.completed()) {
158 return PendFrom<kTupleIndex + 1>(cx, has_active_pendable);
162 PendOutputOf<std::tuple_element_t<kTupleIndex,
decltype(pendables_)>>;
163 Poll<value_type> result = pendable.Pend(cx);
165 if (result.IsReady()) {
166 return Ready(ResultVariant(
167 std::in_place_index<kTupleIndex>,
168 SelectResult<kTupleIndex, value_type>(std::move(*result))));
170 return PendFrom<kTupleIndex + 1>(cx,
true);
174 if (!has_active_pendable) {
175 return Ready(AllPendablesCompleted{});
181 std::tuple<Pendables...> pendables_;
184template <
typename... Pendables>
185Selector(Pendables&&...) -> Selector<Pendables...>;
191template <
typename... Pendables>
193 Selector selector(std::forward<Pendables>(pendables)...);
194 return selector.
Pend(cx);
199template <
typename ResultVariant,
200 typename AllPendablesCompletedHandler,
201 typename... ReadyHandler>
203 ResultVariant&& variant,
204 AllPendablesCompletedHandler&& on_all_pendables_completed,
205 ReadyHandler&&... on_ready) {
206 static_assert(std::variant_size_v<std::decay_t<ResultVariant>> - 1 ==
207 sizeof...(ReadyHandler),
208 "Number of handlers must match the number of pendables.");
209 internal::VisitSelectResult(
210 std::forward<ResultVariant>(variant),
211 std::forward<AllPendablesCompletedHandler>(on_all_pendables_completed),
212 std::forward_as_tuple(std::forward<ReadyHandler>(on_ready)...),
213 std::make_index_sequence<
sizeof...(ReadyHandler)>{});
Poll< ResultVariant > Pend(Context &cx)
Definition: select.h:146
void VisitSelectResult(ResultVariant &&variant, AllPendablesCompletedHandler &&on_all_pendables_completed, ReadyHandler &&... on_ready)
Definition: select.h:202
auto Select(Context &cx, Pendables &&... pendables)
Definition: select.h:192
constexpr PendingType Pending()
Returns a value indicating that an operation was not yet able to complete.
Definition: poll.h:271
constexpr Poll Ready()
Returns a value indicating completion.
Definition: poll.h:255
Indicates that every pendable within a Selector has completed.
Definition: select.h:46