21#include "pw_async2/dispatcher.h"
22#include "pw_async2/future.h"
23#include "pw_async2/poll.h"
24#include "pw_containers/optional_tuple.h"
30template <
typename... Pendables>
33template <
typename... Futures>
39template <
size_t I,
typename T>
41 static constexpr size_t kIndex = I;
45 template <
typename... Pendables>
47 template <
typename... Futures>
50 explicit SelectResult(T&& val) : value(std::move(val)) {}
55 static constexpr size_t kIndex = std::numeric_limits<size_t>::max();
56 std::nullopt_t value = std::nullopt;
63template <
typename Is,
typename... Pendables>
66template <
size_t... Is,
typename... Pendables>
68 using type = std::variant<SelectResult<Is, PendOutputOf<Pendables>>...,
72template <
typename ResultVariant,
73 typename AllPendablesCompletedHandler,
74 typename ReadyHandlers,
76void VisitSelectResult(ResultVariant&& variant,
77 AllPendablesCompletedHandler&& all_completed,
78 ReadyHandlers&& ready_handlers,
79 std::index_sequence<Is...>) {
82 using ArgType = std::decay_t<
decltype(arg)>;
83 if constexpr (std::is_same_v<ArgType, AllPendablesCompleted>) {
84 std::invoke(std::forward<AllPendablesCompletedHandler>(all_completed),
87 std::invoke(std::get<ArgType::kIndex>(
88 std::forward<ReadyHandlers>(ready_handlers)),
89 std::move(arg.value));
92 std::forward<ResultVariant>(variant));
137template <
typename... Pendables>
138class [[deprecated(
"Use future-based Select instead")]]
Selector {
140 static_assert(
sizeof...(Pendables) > 0,
141 "Cannot select over an empty set of pendables");
144 std::make_index_sequence<
sizeof...(Pendables)>,
150 : pendables_(std::move(pendables)...) {}
160 template <
size_t kTupleIndex>
162 if constexpr (kTupleIndex <
sizeof...(Pendables)) {
163 auto& pendable = std::get<kTupleIndex>(pendables_);
165 if (pendable.completed()) {
166 return PendFrom<kTupleIndex + 1>(cx, has_active_pendable);
169 using value_type = internal::PendOutputOf<
170 std::tuple_element_t<kTupleIndex,
decltype(pendables_)>>;
171 Poll<value_type> result = pendable.Pend(cx);
173 if (result.IsReady()) {
174 return Ready(ResultVariant(
175 std::in_place_index<kTupleIndex>,
176 SelectResult<kTupleIndex, value_type>(std::move(*result))));
178 return PendFrom<kTupleIndex + 1>(cx,
true);
182 if (!has_active_pendable) {
183 return Ready(AllPendablesCompleted{});
189 std::tuple<Pendables...> pendables_;
192template <
typename... Pendables>
193Selector(Pendables&&...) -> Selector<Pendables...>;
199template <
typename... Pendables>
200[[deprecated(
"Use future-based Select instead")]]
202 Selector selector(std::forward<Pendables>(pendables)...);
203 return selector.
Pend(cx);
208template <
typename ResultVariant,
209 typename AllPendablesCompletedHandler,
210 typename... ReadyHandler>
212 ResultVariant&& variant,
213 AllPendablesCompletedHandler&& on_all_pendables_completed,
214 ReadyHandler&&... on_ready) {
215 static_assert(std::variant_size_v<std::decay_t<ResultVariant>> - 1 ==
216 sizeof...(ReadyHandler),
217 "Number of handlers must match the number of pendables.");
218 internal::VisitSelectResult(
219 std::forward<ResultVariant>(variant),
220 std::forward<AllPendablesCompletedHandler>(on_all_pendables_completed),
221 std::forward_as_tuple(std::forward<ReadyHandler>(on_ready)...),
222 std::make_index_sequence<
sizeof...(ReadyHandler)>{});
224template <
typename... Futures>
226 :
public Future<SelectFuture<Futures...>,
227 OptionalTuple<typename Futures::value_type...>> {
229 static_assert(
sizeof...(Futures) > 0,
230 "Cannot select over an empty set of futures");
236 : futures_(std::move(futures)...) {}
241 static constexpr auto kTupleIndexSequence =
242 std::make_index_sequence<
sizeof...(Futures)>();
246 PendAll(cx, kTupleIndexSequence, tuple);
247 if (!tuple.
empty()) {
253 void DoMarkComplete() {}
254 bool DoIsComplete()
const {
return IsComplete<0>(); }
256 template <
size_t kTupleIndex>
257 bool IsComplete()
const {
258 if constexpr (kTupleIndex <
sizeof...(Futures)) {
259 auto& future = std::get<kTupleIndex>(futures_);
260 if (future.is_complete()) {
263 return IsComplete<kTupleIndex + 1>();
271 template <
size_t... Is>
273 (PendFuture<Is>(cx, result), ...);
276 template <
size_t kTupleIndex>
278 auto& future = std::get<kTupleIndex>(futures_);
279 if (future.is_complete()) {
283 auto poll = future.Pend(cx);
284 if (poll.IsReady()) {
285 result.template emplace<kTupleIndex>(std::move(*poll));
289 std::tuple<Futures...> futures_;
292template <
typename... Futures>
300template <
typename... Futures>
302 static_assert(std::conjunction_v<is_future<Futures>...>,
303 "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:154
void VisitSelectResult(ResultVariant &&variant, AllPendablesCompletedHandler &&on_all_pendables_completed, ReadyHandler &&... on_ready)
Definition: select.h:211
SelectFuture< Futures... > Select(Futures &&... futures)
Definition: select.h:301
auto SelectPendable(Context &cx, Pendables &&... pendables)
Definition: select.h:201
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:54