C/C++ API Reference
Loading...
Searching...
No Matches
select.h
1// Copyright 2025 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <algorithm>
17#include <tuple>
18#include <utility>
19#include <variant>
20
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"
25
26namespace pw::async2 {
27
29
30template <typename... Futures>
32 public:
33 static_assert(sizeof...(Futures) > 0,
34 "Cannot select over an empty set of futures");
35
36 using value_type = OptionalTuple<typename Futures::value_type...>;
37
38 constexpr SelectFuture() = default;
39
40 explicit SelectFuture(Futures&&... futures)
41 : futures_(std::move(futures)...), state_(FutureState::kPending) {}
42
43 Poll<value_type> Pend(Context& cx) {
44 value_type tuple;
45 PendAll(cx, kTupleIndexSequence, tuple);
46 if (!tuple.empty()) {
47 state_.MarkComplete();
48 futures_ = std::tuple<Futures...>();
49 return tuple;
50 }
51 return Pending();
52 }
53
54 [[nodiscard]] constexpr bool is_pendable() const {
55 return state_.is_pendable();
56 }
57 [[nodiscard]] constexpr bool is_complete() const {
58 return state_.is_complete();
59 }
60
61 private:
62 static constexpr auto kTupleIndexSequence =
63 std::make_index_sequence<sizeof...(Futures)>();
64
65 enum State : uint8_t {
66 kDefaultConstructed,
67 kPendable,
68 kComplete,
69 };
70
73 template <size_t... Is>
74 void PendAll(Context& cx, std::index_sequence<Is...>, value_type& result) {
75 (PendFuture<Is>(cx, result), ...);
76 }
77
78 template <size_t kTupleIndex>
79 void PendFuture(Context& cx, value_type& result) {
80 auto& future = std::get<kTupleIndex>(futures_);
81 if (future.is_complete()) {
82 return;
83 }
84
85 auto poll = future.Pend(cx);
86 if (poll.IsReady()) {
87 result.template emplace<kTupleIndex>(std::move(*poll));
88 }
89 }
90
91 std::tuple<Futures...> futures_;
92 FutureState state_;
93};
94
95template <typename... Futures>
96SelectFuture(Futures&&...) -> SelectFuture<Futures...>;
97
103template <typename... Futures>
104SelectFuture<Futures...> Select(Futures&&... futures) {
105 static_assert((Future<Futures> && ...),
106 "All arguments to Select must be Future types");
107 return SelectFuture(std::forward<Futures>(futures)...);
108}
109
111
112} // namespace pw::async2
Definition: optional_tuple.h:112
constexpr bool empty() const
Checks if the OptionalTuple contains no active elements.
Definition: optional_tuple.h:180
Definition: context.h:46
Definition: future.h:111
constexpr bool is_pendable() const
Definition: future.h:156
constexpr bool is_complete() const
Definition: future.h:162
Definition: poll.h:138
Definition: select.h:31
Definition: future.h:47
SelectFuture< Futures... > Select(Futures &&... futures)
Definition: select.h:104
constexpr PendingType Pending()
Returns a value indicating that an operation was not yet able to complete.
Definition: poll.h:353