C/C++ API Reference
Loading...
Searching...
No Matches
join.h
1// Copyright 2024 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 "pw_async2/dispatcher.h"
17#include "pw_async2/future.h"
18
19namespace pw::async2 {
20
22
23template <typename... Futures>
25 public:
26 using value_type = std::tuple<FutureValue<Futures>...>;
27
28 constexpr JoinFuture()
30
31 [[nodiscard]] bool is_pendable() const { return state_.is_pendable(); }
32
33 [[nodiscard]] bool is_complete() const { return state_.is_complete(); }
34
38 PW_ASSERT(is_pendable());
39 if (!PendElements(cx, kTupleIndexSequence)) {
40 return Pending();
41 }
42
43 state_.MarkComplete();
44 return TakeOutputs(kTupleIndexSequence);
45 }
46
47 private:
48 static_assert(sizeof...(Futures) > 0u, "Cannot join an empty set of futures");
49
50 static constexpr auto kTupleIndexSequence =
51 std::make_index_sequence<sizeof...(Futures)>();
52 using TupleOfOutputValues = std::tuple<FutureValue<Futures>...>;
53
54 template <typename... Fs>
55 friend constexpr auto Join(Fs&&...);
56
57 explicit constexpr JoinFuture(Futures&&... futures)
58 : futures_(std::move(futures)...),
59 outputs_(Poll<typename Futures::value_type>(Pending())...),
60 state_(FutureState::kPending) {}
61
65 template <size_t... Is>
66 bool PendElements(Context& cx, std::index_sequence<Is...>) {
67 (PendElement<Is>(cx), ...);
68 return (std::get<Is>(outputs_).IsReady() && ...);
69 }
70
73 template <size_t kTupleIndex>
74 void PendElement(Context& cx) {
75 auto& output = std::get<kTupleIndex>(outputs_);
76 if (!output.IsReady()) {
77 output = std::get<kTupleIndex>(futures_).Pend(cx);
78 }
79 }
80
82 template <size_t... Is>
83 Poll<TupleOfOutputValues> TakeOutputs(std::index_sequence<Is...>) {
84 return Poll<TupleOfOutputValues>(
85 std::tuple<FutureValue<Futures>...>(TakeOutput<Is>()...));
86 }
87
89 template <size_t kTupleIndex>
91 typename std::tuple_element<kTupleIndex, std::tuple<Futures...>>::type>&&
92 TakeOutput() {
93 return std::move(std::get<kTupleIndex>(outputs_).value());
94 }
95
96 static_assert((Future<Futures> && ...),
97 "All types in JoinFuture must be Future types");
98 std::tuple<Futures...> futures_;
99 std::tuple<Poll<typename Futures::value_type>...> outputs_;
100 FutureState state_;
101};
102
103template <typename... Futures>
104JoinFuture(Futures&&...) -> JoinFuture<Futures...>;
105
111template <typename... Futures>
112constexpr auto Join(Futures&&... futures) {
113 static_assert((Future<Futures> && ...),
114 "All arguments to Join must be Future types");
115 return JoinFuture(std::forward<Futures>(futures)...);
116}
117
119
120} // namespace pw::async2
Definition: context.h:46
Definition: future.h:113
constexpr bool is_pendable() const
Definition: future.h:151
void MarkComplete()
Definition: future.h:185
constexpr bool is_complete() const
Definition: future.h:156
Definition: join.h:24
Poll< value_type > Pend(Context &cx)
Definition: join.h:37
Definition: poll.h:138
Definition: future.h:47
constexpr auto Join(Futures &&... futures)
Definition: join.h:112
std::conditional_t< std::is_void_v< typename T::value_type >, ReadyType, typename T::value_type > FutureValue
Definition: future.h:109
constexpr PendingType Pending()
Returns a value indicating that an operation was not yet able to complete.
Definition: poll.h:353