20#include "pw_assert/assert.h"
21#include "pw_async2/context.h"
22#include "pw_async2/poll.h"
23#include "pw_containers/intrusive_list.h"
24#include "pw_memory/container_of.h"
25#include "pw_sync/interrupt_spin_lock.h"
64template <
typename Derived,
typename T>
67 using value_type = std::conditional_t<std::is_void_v<T>,
ReadyType, T>;
80 derived().DoMarkComplete();
91 constexpr Future() =
default;
94 Derived& derived() {
return static_cast<Derived&
>(*this); }
95 const Derived& derived()
const {
return static_cast<const Derived&
>(*this); }
98template <
typename T,
typename =
void>
104 std::void_t<typename T::value_type,
105 decltype(std::declval<T&>().Pend(std::declval<Context&>())),
106 decltype(std::declval<const T&>().is_complete())>>
107 : std::is_convertible<decltype(&T::Pend),
108 Poll<typename T::value_type> (T::*)(Context&)> {};
111constexpr bool is_future_v =
137template <
typename FutureType,
typename Lock = sync::InterruptSpinLock>
146 void Push(FutureType& future) {
147 std::lock_guard
lock(lock_);
152 std::optional<std::reference_wrapper<FutureType>>
Pop() {
153 std::lock_guard
lock(lock_);
154 if (futures_.
empty()) {
157 FutureType& future = futures_.
front();
159 return std::ref(future);
164 std::lock_guard
lock(lock_);
165 return futures_.
empty();
174 template <
typename,
typename>
177 using LockType = Lock;
194template <
typename FutureType>
203 void Set(FutureType& future) {
218 [[nodiscard]] std::optional<std::reference_wrapper<FutureType>>
Take() {
226 template <
typename,
typename>
283template <
typename Derived,
typename T>
285 :
public Future<ListableFutureWithWaker<Derived, T>, T>,
297 if (provider_ !=
nullptr) {
298 provider_->lock().lock();
303 if (provider_ !=
nullptr) {
304 provider_->lock().unlock();
309 provider_ = provider;
315 PW_ASSERT(provider_ !=
nullptr);
319 PW_ASSERT(provider_ !=
nullptr);
323 explicit operator bool()
const {
return provider_ !=
nullptr; }
329 : provider_(provider) {}
352 : provider_(nullptr), complete_(state == kMovedFrom) {}
355 : provider_(&provider) {
356 provider.
Push(derived());
358 explicit ListableFutureWithWaker(SingleFutureProvider<Derived>& single)
359 : ListableFutureWithWaker(single.inner_) {}
361 ~ListableFutureWithWaker() {
365 std::lock_guard guard(lock());
366 if (!this->unlisted()) {
371 void MoveFrom(ListableFutureWithWaker& other) {
372 complete_ = std::exchange(other.complete_,
true);
373 provider_ = std::exchange(other.provider_,
nullptr);
374 waker_ = std::move(other.waker_);
377 std::lock_guard guard(lock());
378 if (!other.unlisted()) {
379 this->replace(other);
384 ListFutureProvider<Derived>& provider() {
return *provider_; }
386 Lock& lock() {
return provider_; }
399 std::is_same_v<std::remove_extent_t<
decltype(Derived::kWaitReason)>,
401 "kWaitReason must be a character array");
413 std::lock_guard guard(lock());
414 if (provider_ && this->unlisted()) {
415 provider_->futures_.
push_back(derived());
419 void DoMarkComplete() { complete_ =
true; }
420 bool DoIsComplete()
const {
return complete_; }
422 Derived& derived() {
return static_cast<Derived&
>(*this); }
426 bool complete_ =
false;
442 constexpr FutureCore() : state_(State::kNull) {}
472 [[nodiscard]]
bool is_pendable()
const {
return state_ > State::kComplete; }
476 [[nodiscard]]
bool is_complete()
const {
return state_ == State::kComplete; }
482 [[nodiscard]]
bool is_ready()
const {
return state_ == State::kReady; }
492 state_ = State::kReady;
498 template <
typename FutureType>
502 auto poll = future.DoPend(cx);
506 state_ = State::kComplete;
513 [[nodiscard]]
bool in_list()
const {
return !unlisted(); }
519 [[nodiscard]]
bool is_initialized()
const {
return state_ != State::kNull; }
523 enum class State :
unsigned char {
551 bool empty()
const {
return list_.empty(); }
559 FutureCore* PopIfAvailable() {
return list_.empty() ? nullptr : &Pop(); }
570 list_.front().WakeAndMarkReady();
574 void ResolveOneIfAvailable() {
575 if (!list_.empty()) {
597template <auto kGetFutureImpl, auto kGetFutureCore>
600 using value_type = std::remove_reference_t<
decltype(*kGetFutureImpl(
601 std::declval<FutureCore*>()))>;
602 using pointer = value_type*;
603 using reference = value_type&;
607 void Push(
FutureCore& future) { BaseFutureList::Push(future); }
608 void Push(reference future) { Push(kGetFutureCore(future)); }
611 BaseFutureList::PushRequireEmpty(future);
613 void PushRequireEmpty(reference future) {
614 PushRequireEmpty(kGetFutureCore(future));
618 return BaseFutureList::PushIfEmpty(future);
620 bool PushIfEmpty(reference future) {
621 return PushIfEmpty(kGetFutureCore(future));
624 pointer PopIfAvailable() {
625 return kGetFutureImpl(BaseFutureList::PopIfAvailable());
628 reference Pop() {
return *kGetFutureImpl(BaseFutureList::PopIfAvailable()); }
630 template <
typename Resolver>
631 void ResolveAllWith(Resolver&& resolver) {
632 while (!list().empty()) {
637 template <
typename Resolver>
638 void ResolveOneWith(Resolver&& resolver) {
639 if (!list().empty()) {
649template <auto kMemberPtr>
Definition: intrusive_forward_list.h:99
void ResolveOne()
Definition: future.h:569
void ResolveAll()
Pops all futures and calls WakeAndMarkReady() on them.
Pending
Tag type to construct an active FutureCore. Pend may be called.
Definition: future.h:453
constexpr FutureCore(ReadyForCompletion)
Definition: future.h:464
constexpr FutureCore(Pending)
Definition: future.h:460
bool is_ready() const
Definition: future.h:482
void WakeAndMarkReady()
Definition: future.h:490
bool is_complete() const
Definition: future.h:476
ReadyForCompletion
Definition: future.h:450
void Wake()
Definition: future.h:486
bool is_pendable() const
Definition: future.h:472
void Unlist()
Removes this future from its list, if it is in one.
Definition: future.h:496
bool in_list() const
Definition: future.h:513
Poll< value_type > Pend(Context &cx)
Definition: future.h:76
bool is_complete() const
Definition: future.h:88
bool empty()
Returns true if there are no futures listed.
Definition: future.h:163
Lock & lock()
Provides access to the list's internal lock.
Definition: future.h:169
void Push(FutureType &future)
Adds a future to the end of the list.
Definition: future.h:146
std::optional< std::reference_wrapper< FutureType > > Pop()
Removes and returns the first future from the list, if one exists.
Definition: future.h:152
void Wake()
Wakes the task waiting on the future.
Definition: future.h:389
ListableFutureWithWaker(ConstructedState state)
Definition: future.h:351
ConstructedState
Tag to prevent accidental default construction.
Definition: future.h:337
bool has_future()
Returns true if the provider has a future.
Definition: future.h:223
bool TrySet(FutureType &future)
Attempts to set the provider's future, returning true if successful.
Definition: future.h:209
std::optional< std::reference_wrapper< FutureType > > Take()
Claims the provider's future, leaving it unset.
Definition: future.h:218
void Set(FutureType &future)
Sets the provider's future. Crashes if a future is already set.
Definition: future.h:203
Definition: intrusive_list.h:88
constexpr bool IsReady() const noexcept
Returns whether or not this value is Ready.
Definition: poll.h:133
constexpr bool IsPending() const noexcept
Returns whether or not this value is Pending.
Definition: poll.h:136
#define PW_ASYNC_STORE_WAKER(context, waker_or_queue_out, wait_reason_string)
Definition: waker.h:60
void push_back(T &item)
Inserts an element at the end of the list.
Definition: intrusive_list.h:255
void PushBackSlow(IntrusiveForwardList< T > &forward_list, T &item)
Inserts an element at the end of the forward list. Runs in O(n) time.
Definition: intrusive_forward_list.h:50
bool empty() const noexcept
Definition: intrusive_list.h:207
void pop_front()
Removes the first item in the list. The list must not be empty.
Definition: intrusive_list.h:264
T & front()
Reference to the first element in the list. Undefined behavior if empty().
Definition: intrusive_list.h:167
#define PW_LOCKABLE(name)
Definition: lock_annotations.h:208
#define PW_NO_LOCK_SAFETY_ANALYSIS
Definition: lock_annotations.h:292
#define PW_EXCLUSIVE_LOCK_FUNCTION(...)
Definition: lock_annotations.h:230
#define PW_UNLOCK_FUNCTION(...)
Definition: lock_annotations.h:247