21#include "pw_async2/dispatcher.h"
22#include "pw_async2/future.h"
23#include "pw_containers/optional_tuple.h"
29template <
typename... Pendables>
32namespace experimental {
34template <
typename... Futures>
42template <
size_t I,
typename T>
44 static constexpr size_t kIndex = I;
48 template <
typename... Pendables>
50 template <
typename... Futures>
53 explicit SelectResult(T&& val) : value(std::move(val)) {}
58 static constexpr size_t kIndex = std::numeric_limits<size_t>::max();
59 std::nullopt_t value = std::nullopt;
66template <
typename Is,
typename... Pendables>
69template <
size_t... Is,
typename... Pendables>
71 using type = std::variant<SelectResult<Is, PendOutputOf<Pendables>>...,
75template <
typename ResultVariant,
76 typename AllPendablesCompletedHandler,
77 typename ReadyHandlers,
79void VisitSelectResult(ResultVariant&& variant,
80 AllPendablesCompletedHandler&& all_completed,
81 ReadyHandlers&& ready_handlers,
82 std::index_sequence<Is...>) {
85 using ArgType = std::decay_t<
decltype(arg)>;
86 if constexpr (std::is_same_v<ArgType, AllPendablesCompleted>) {
87 std::invoke(std::forward<AllPendablesCompletedHandler>(all_completed),
90 std::invoke(std::get<ArgType::kIndex>(
91 std::forward<ReadyHandlers>(ready_handlers)),
92 std::move(arg.value));
95 std::forward<ResultVariant>(variant));
140template <
typename... Pendables>
143 static_assert(
sizeof...(Pendables) > 0,
144 "Cannot select over an empty set of pendables");
147 std::make_index_sequence<
sizeof...(Pendables)>,
153 : pendables_(std::move(pendables)...) {}
163 template <
size_t kTupleIndex>
165 if constexpr (kTupleIndex <
sizeof...(Pendables)) {
166 auto& pendable = std::get<kTupleIndex>(pendables_);
168 if (pendable.completed()) {
169 return PendFrom<kTupleIndex + 1>(cx, has_active_pendable);
173 PendOutputOf<std::tuple_element_t<kTupleIndex,
decltype(pendables_)>>;
174 Poll<value_type> result = pendable.Pend(cx);
176 if (result.IsReady()) {
177 return Ready(ResultVariant(
178 std::in_place_index<kTupleIndex>,
179 SelectResult<kTupleIndex, value_type>(std::move(*result))));
181 return PendFrom<kTupleIndex + 1>(cx,
true);
185 if (!has_active_pendable) {
186 return Ready(AllPendablesCompleted{});
192 std::tuple<Pendables...> pendables_;
195template <
typename... Pendables>
196Selector(Pendables&&...) -> Selector<Pendables...>;
202template <
typename... Pendables>
204 Selector selector(std::forward<Pendables>(pendables)...);
205 return selector.
Pend(cx);
210template <
typename ResultVariant,
211 typename AllPendablesCompletedHandler,
212 typename... ReadyHandler>
214 ResultVariant&& variant,
215 AllPendablesCompletedHandler&& on_all_pendables_completed,
216 ReadyHandler&&... on_ready) {
217 static_assert(std::variant_size_v<std::decay_t<ResultVariant>> - 1 ==
218 sizeof...(ReadyHandler),
219 "Number of handlers must match the number of pendables.");
220 internal::VisitSelectResult(
221 std::forward<ResultVariant>(variant),
222 std::forward<AllPendablesCompletedHandler>(on_all_pendables_completed),
223 std::forward_as_tuple(std::forward<ReadyHandler>(on_ready)...),
224 std::make_index_sequence<
sizeof...(ReadyHandler)>{});
229namespace experimental {
231template <
typename... Futures>
233 :
public Future<SelectFuture<Futures...>,
234 OptionalTuple<typename Futures::value_type...>> {
236 static_assert(
sizeof...(Futures) > 0,
237 "Cannot select over an empty set of futures");
243 : futures_(std::move(futures)...) {}
248 static constexpr auto kTupleIndexSequence =
249 std::make_index_sequence<
sizeof...(Futures)>();
253 PendAll(cx, kTupleIndexSequence, tuple);
254 if (!tuple.
empty()) {
260 void DoMarkComplete() {}
261 bool DoIsComplete()
const {
return IsComplete<0>(); }
263 template <
size_t kTupleIndex>
264 bool IsComplete()
const {
265 if constexpr (kTupleIndex <
sizeof...(Futures)) {
266 auto& future = std::get<kTupleIndex>(futures_);
267 if (future.is_complete()) {
270 return IsComplete<kTupleIndex + 1>();
278 template <
size_t... Is>
280 (PendFuture<Is>(cx, result), ...);
283 template <
size_t kTupleIndex>
285 auto& future = std::get<kTupleIndex>(futures_);
286 if (future.is_complete()) {
290 auto poll = future.Pend(cx);
291 if (poll.IsReady()) {
292 result.template emplace<kTupleIndex>(std::move(*poll));
296 std::tuple<Futures...> futures_;
299template <
typename... Futures>
307template <
typename... Futures>
309 static_assert(std::conjunction_v<is_future<Futures>...>,
310 "All arguments to Select must be Future types");
Definition: optional_tuple.h:112
constexpr bool empty() const
Checks if the OptionalTuple contains no active elements.
Definition: optional_tuple.h:180
Poll< ResultVariant > Pend(Context &cx)
Definition: select.h:157
void VisitSelectResult(ResultVariant &&variant, AllPendablesCompletedHandler &&on_all_pendables_completed, ReadyHandler &&... on_ready)
Definition: select.h:213
auto Select(Context &cx, Pendables &&... pendables)
Definition: select.h:203
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:57