C/C++ API Reference
Loading...
Searching...
No Matches
value_future.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 <mutex>
17#include <optional>
18#include <type_traits>
19
20#include "pw_assert/assert.h"
21#include "pw_async2/future.h"
22#include "pw_polyfill/language_feature_macros.h"
23#include "pw_sync/interrupt_spin_lock.h"
24
25namespace pw::async2 {
26namespace internal {
27
28inline sync::InterruptSpinLock& ValueProviderLock() {
29 PW_CONSTINIT static sync::InterruptSpinLock lock;
30 return lock;
31}
32
33bool PendValueFutureCore(FutureCore& core, Context& cx)
34 PW_EXCLUSIVE_LOCKS_REQUIRED(ValueProviderLock());
35
36} // namespace internal
37
38template <typename T>
39class ValueProvider;
40template <typename T>
41class BroadcastValueProvider;
42
44
50template <typename T>
52 public:
53 using value_type = T;
54
55 constexpr ValueFuture() = default;
56
57 ValueFuture(ValueFuture&& other) noexcept
58 PW_LOCKS_EXCLUDED(internal::ValueProviderLock()) {
59 *this = std::move(other);
60 }
61
62 ValueFuture& operator=(ValueFuture&& other) noexcept
63 PW_LOCKS_EXCLUDED(internal::ValueProviderLock()) {
64 if (this != &other) {
65 std::lock_guard lock(internal::ValueProviderLock());
66 core_ = std::move(other.core_);
67 value_ = std::move(other.value_);
68 }
69 return *this;
70 }
71
72 ~ValueFuture() PW_LOCKS_EXCLUDED(internal::ValueProviderLock()) {
73 std::lock_guard lock(internal::ValueProviderLock());
74 core_.Unlist();
75 }
76
79 template <typename... Args>
80 static ValueFuture Resolved(Args&&... args) {
81 return ValueFuture(std::in_place, std::forward<Args>(args)...);
82 }
83
84 Poll<T> Pend(Context& cx) {
85 // ValueFuture uses a global lock so that futures don't have to access their
86 // provider to get a lock after they're completed. This ensures the
87 // ValueFuture never needs to access the provider.
88 //
89 // With some care (and complexity), the lock could be moved to the provider.
90 // A global lock is simpler and more efficient in practice.
91 std::lock_guard lock(internal::ValueProviderLock());
92 if (internal::PendValueFutureCore(core_, cx)) {
93 return Pending();
94 }
95 return Ready(std::move(*value_));
96 }
97
98 [[nodiscard]] bool is_pendable() const {
99 std::lock_guard lock(internal::ValueProviderLock());
100 return core_.is_pendable();
101 }
102
103 [[nodiscard]] bool is_complete() const {
104 std::lock_guard lock(internal::ValueProviderLock());
105 return core_.is_complete();
106 }
107
108 private:
109 friend class ValueProvider<T>;
110 friend class BroadcastValueProvider<T>;
111
112 template <typename... Args>
113 explicit ValueFuture(std::in_place_t, Args&&... args)
114 : core_(FutureState::kReadyForCompletion),
115 value_(std::in_place, std::forward<Args>(args)...) {}
116
117 ValueFuture(FutureState::Pending) : core_(FutureState::kPending) {}
118
119 template <typename... Args>
120 void ResolveLocked(Args&&... args)
121 PW_EXCLUSIVE_LOCKS_REQUIRED(internal::ValueProviderLock()) {
122 // SAFETY: This is only called from FutureList with the lock held.
123 PW_DASSERT(!value_.has_value());
124 value_.emplace(std::forward<Args>(args)...);
125 core_.WakeAndMarkReady();
126 }
127
128 FutureCore core_ PW_GUARDED_BY(internal::ValueProviderLock());
129 std::optional<T> value_ PW_GUARDED_BY(internal::ValueProviderLock());
130};
131
134template <>
135class ValueFuture<void> {
136 public:
137 using value_type = void;
138
139 constexpr ValueFuture() = default;
140
141 ValueFuture(ValueFuture&& other) noexcept
142 PW_LOCKS_EXCLUDED(internal::ValueProviderLock()) {
143 *this = std::move(other);
144 }
145
146 ValueFuture& operator=(ValueFuture&& other) noexcept
147 PW_LOCKS_EXCLUDED(internal::ValueProviderLock()) {
148 if (this != &other) {
149 std::lock_guard lock(internal::ValueProviderLock());
150 core_ = std::move(other.core_);
151 }
152 return *this;
153 }
154
155 ~ValueFuture() PW_LOCKS_EXCLUDED(internal::ValueProviderLock()) {
156 std::lock_guard lock(internal::ValueProviderLock());
157 core_.Unlist();
158 }
159
160 Poll<> Pend(Context& cx) {
161 std::lock_guard lock(internal::ValueProviderLock());
162 if (internal::PendValueFutureCore(core_, cx)) {
163 return Pending();
164 }
165 return Ready();
166 }
167
168 [[nodiscard]] bool is_pendable() const {
169 std::lock_guard lock(internal::ValueProviderLock());
170 return core_.is_pendable();
171 }
172
173 [[nodiscard]] bool is_complete() const {
174 std::lock_guard lock(internal::ValueProviderLock());
175 return core_.is_complete();
176 }
177
178 static ValueFuture Resolved() {
179 return ValueFuture(FutureState::kReadyForCompletion);
180 }
181
182 private:
183 friend class ValueProvider<void>;
184 friend class BroadcastValueProvider<void>;
185
187 : core_(FutureState::kReadyForCompletion) {}
188
189 explicit ValueFuture(FutureState::Pending) : core_(FutureState::kPending) {}
190
191 FutureCore core_ PW_GUARDED_BY(internal::ValueProviderLock());
192};
193
196
198template <typename T>
200
215template <typename T>
217 public:
218 constexpr BroadcastValueProvider() = default;
219
221 PW_LOCKS_EXCLUDED(internal::ValueProviderLock()) {
222 std::lock_guard lock(internal::ValueProviderLock());
223 list_ = std::move(other.list_);
224 }
225
226 BroadcastValueProvider& operator=(BroadcastValueProvider&& other) noexcept
227 PW_LOCKS_EXCLUDED(internal::ValueProviderLock()) {
228 if (this != &other) {
229 std::lock_guard lock(internal::ValueProviderLock());
230 PW_ASSERT(list_.empty()); // ensure any futures were resolved
231 list_ = std::move(other.list_);
232 }
233 return *this;
234 }
235
237 BroadcastValueProvider& operator=(const BroadcastValueProvider&) = delete;
238
239 ~BroadcastValueProvider() { PW_ASSERT(list_.empty()); }
240
245 ValueFuture<T> future(FutureState::kPending);
246 {
247 std::lock_guard lock(internal::ValueProviderLock());
248 list_.Push(future.core_);
249 }
250 return future;
251 }
252
254 template <typename U = T, std::enable_if_t<!std::is_void_v<U>, int> = 0>
255 void Resolve(const U& value) {
256 std::lock_guard lock(internal::ValueProviderLock());
257 list_.ResolveAllWith(
258 [&](ValueFuture<T>& future)
259 PW_NO_LOCK_SAFETY_ANALYSIS { future.ResolveLocked(value); });
260 }
261
263 template <typename U = T, std::enable_if_t<std::is_void_v<U>, int> = 0>
264 void Resolve() {
265 std::lock_guard lock(internal::ValueProviderLock());
266 list_.ResolveAll();
267 }
268
269 private:
271 PW_GUARDED_BY(internal::ValueProviderLock());
272};
273
285template <typename T>
287 public:
288 constexpr ValueProvider() = default;
289
290 ValueProvider(ValueProvider&& other) noexcept
291 PW_LOCKS_EXCLUDED(internal::ValueProviderLock()) {
292 std::lock_guard lock(internal::ValueProviderLock());
293 list_ = std::move(other.list_);
294 }
295
296 ValueProvider& operator=(ValueProvider&& other) noexcept
297 PW_LOCKS_EXCLUDED(internal::ValueProviderLock()) {
298 if (this != &other) {
299 std::lock_guard lock(internal::ValueProviderLock());
300 PW_ASSERT(list_.empty()); // ensure any futures were resolved
301 list_ = std::move(other.list_);
302 }
303 return *this;
304 }
305
306 ValueProvider(const ValueProvider&) = delete;
307 ValueProvider& operator=(const ValueProvider&) = delete;
308
309 ~ValueProvider() { PW_ASSERT(list_.empty()); }
310
315 ValueFuture<T> future(FutureState::kPending);
316 {
317 std::lock_guard lock(internal::ValueProviderLock());
318 list_.PushRequireEmpty(future.core_);
319 }
320 return future;
321 }
322
327 std::optional<ValueFuture<T>> TryGet() {
328 ValueFuture<T> future(FutureState::kPending);
329 {
330 std::lock_guard lock(internal::ValueProviderLock());
331 if (!list_.PushIfEmpty(future.core_)) {
332 return std::nullopt;
333 }
334 }
335 return future;
336 }
337
339 bool has_future() const {
340 std::lock_guard lock(internal::ValueProviderLock());
341 return !list_.empty();
342 }
343
346 template <typename... Args,
347 typename U = T,
348 std::enable_if_t<!std::is_void_v<U>, int> = 0>
349 void Resolve(Args&&... args) {
350 std::lock_guard lock(internal::ValueProviderLock());
351 if (ValueFuture<T>* future = list_.PopIfAvailable(); future != nullptr) {
352 future->ResolveLocked(std::forward<Args>(args)...);
353 };
354 }
355
357 template <typename U = T, std::enable_if_t<std::is_void_v<U>, int> = 0>
358 void Resolve() {
359 std::lock_guard lock(internal::ValueProviderLock());
360 list_.ResolveOneIfAvailable();
361 }
362
363 private:
365 PW_GUARDED_BY(internal::ValueProviderLock());
366};
367
372template <typename T>
374 public:
375 OptionalValueProvider() = default;
376
378 OptionalValueProvider& operator=(OptionalValueProvider&& other) {
379 Cancel();
380 provider_ = std::move(other.provider_);
381 return *this;
382 }
383
385 OptionalValueProvider& operator=(const OptionalValueProvider&) = delete;
386
388
391 OptionalValueFuture<T> Get() { return provider_.Get(); }
392
394 template <typename... Args>
395 void Resolve(Args&&... args) {
396 provider_.Resolve(std::in_place, std::forward<Args>(args)...);
397 }
398
400 void Cancel() { provider_.Resolve(std::nullopt); }
401
402 private:
404};
405
410template <typename T>
412 public:
414
418 Cancel();
419 provider_ = std::move(other.provider_);
420 return *this;
421 }
422
424 delete;
426 const OptionalBroadcastValueProvider&) = delete;
427
429
432 OptionalValueFuture<T> Get() { return provider_.Get(); }
433
435 void Resolve(const T& value) { provider_.Resolve(value); }
436
438 void Cancel() { provider_.Resolve(std::nullopt); }
439
440 private:
442};
443
445
446} // namespace pw::async2
Definition: value_future.h:216
ValueFuture< T > Get()
Definition: value_future.h:244
void Resolve(const U &value)
Resolves every pending ValueFuture with a copy of the provided value.
Definition: value_future.h:255
void Resolve()
Resolves every pending ValueFuture.
Definition: value_future.h:264
Definition: task.h:47
Definition: future.h:408
Definition: future.h:228
void WakeAndMarkReady()
Definition: future.h:286
constexpr bool is_pendable() const
Definition: future.h:255
constexpr bool is_complete() const
Definition: future.h:260
void Unlist()
Removes this future from its list, if it is in one.
Definition: future.h:309
Pending
Tag for constructing an active future, for which Pend may be called.
Definition: future.h:117
ReadyForCompletion
Definition: future.h:121
Definition: value_future.h:411
OptionalValueFuture< T > Get()
Definition: value_future.h:432
void Resolve(const T &value)
Resolves all pending ValueFutures with the provided value.
Definition: value_future.h:435
void Cancel()
Resolves all pending ValueFutures with std::nullopt.
Definition: value_future.h:438
Definition: value_future.h:373
void Resolve(Args &&... args)
Resolves the pending ValueFuture by constructing it in-place.
Definition: value_future.h:395
void Cancel()
Resolves the pending ValueFuture with std::nullopt.
Definition: value_future.h:400
OptionalValueFuture< T > Get()
Definition: value_future.h:391
Definition: poll.h:138
Definition: value_future.h:135
Definition: value_future.h:51
static ValueFuture Resolved(Args &&... args)
Definition: value_future.h:80
Definition: value_future.h:286
ValueFuture< T > Get()
Definition: value_future.h:314
void Resolve(Args &&... args)
Definition: value_future.h:349
bool has_future() const
Returns true if the provider stores a pending future.
Definition: value_future.h:339
void Resolve()
Resolves the pending ValueFuture.
Definition: value_future.h:358
std::optional< ValueFuture< T > > TryGet()
Definition: value_future.h:327
constexpr PendingType Pending()
Returns a value indicating that an operation was not yet able to complete.
Definition: poll.h:353
constexpr Poll Ready()
Returns a value indicating completion.
Definition: poll.h:337
#define PW_CONSTINIT
Definition: language_feature_macros.h:52
#define PW_GUARDED_BY(x)
Definition: lock_annotations.h:60
#define PW_NO_LOCK_SAFETY_ANALYSIS
Definition: lock_annotations.h:296
#define PW_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: lock_annotations.h:147
#define PW_LOCKS_EXCLUDED(...)
Definition: lock_annotations.h:178