19#include "lib/stdcompat/type_traits.h"
20#include "pw_allocator/allocator.h"
21#include "pw_async2/callback_task.h"
22#include "pw_async2/dispatcher.h"
23#include "pw_async2/future.h"
24#include "pw_containers/deque.h"
25#include "pw_numeric/checked_arithmetic.h"
26#include "pw_result/result.h"
27#include "pw_sync/interrupt_spin_lock.h"
28#include "pw_sync/lock_annotations.h"
29#include "pw_sync/timed_thread_notification.h"
46class ReserveSendFuture;
51template <
typename T, u
int16_t kCapacity>
82 enum AllowClosed { kAllowClosed };
86 BaseChannelFuture(BaseChannel* channel, AllowClosed)
89 StoreAndAddRefIfNonnull(channel);
92 BaseChannelFuture(BaseChannelFuture&& other)
94 : channel_(other.channel_) {
98 BaseChannelFuture& MoveAssignFrom(BaseChannelFuture& other)
117 void StoreAndAddRefIfNonnull(BaseChannel* channel)
120 void MoveFrom(BaseChannelFuture& other)
123 BaseChannel* channel_;
127 using List = FutureList<&BaseChannelFuture::core_>;
131template <
typename Derived,
typename T,
typename FutureValue>
157 return static_cast<Channel<T>*
>(base_channel());
161 using BaseChannelFuture::base_channel;
162 using BaseChannelFuture::MarkCompleted;
170 chrono::SystemClock::duration::max();
179 std::lock_guard lock(*
this);
180 return is_open_locked();
188 return ref_count_ != 0;
195 std::lock_guard lock(*
this);
202 send_futures_.Push(future);
208 receive_futures_.Push(future);
214 add_object(receiver_count_);
218 add_object(sender_count_);
222 add_object(handle_count_);
230 PW_DASSERT(reservations_ > 0);
235 remove_object(&sender_count_);
239 remove_object(&receiver_count_);
243 remove_object(&handle_count_);
256 receive_futures_.ResolveOneIfAvailable();
260 send_futures_.ResolveOneIfAvailable();
264 return reservations_;
269 if (is_open_locked()) {
286 return handle_count_ == 0 && (sender_count_ == 0 || receiver_count_ == 0);
292 virtual void Destroy() {}
318 using size_type = uint16_t;
326 template <
size_t kAlignment,
size_t kCapacity>
328 : dequeue_(storage) {}
331 [[nodiscard]] size_type capacity()
const {
return dequeue_.capacity(); }
332 [[nodiscard]] size_type size()
const {
return dequeue_.size(); }
333 [[nodiscard]]
bool empty()
const {
return dequeue_.empty(); }
334 [[nodiscard]]
auto deallocator()
const {
return dequeue_.deallocator(); }
335 [[nodiscard]] T& front() {
return dequeue_.front(); }
336 [[nodiscard]]
const T& front()
const {
return dequeue_.front(); }
338 void pop_front() { dequeue_.pop_front(); }
340 template <
typename U>
341 void push_back(U&& value) {
342 dequeue_.push_back(std::forward<U>(value));
345 template <
typename... Args>
346 void emplace_back(Args&&... args) {
347 dequeue_.emplace_back(std::forward<Args>(args)...);
358 using size_type = uint16_t;
367 explicit ChannelDeque(uint16_t capacity) : capacity_(capacity) {}
375 [[nodiscard]] size_type capacity()
const {
return capacity_; }
376 [[nodiscard]] size_type size()
const {
return size_; }
377 [[nodiscard]]
bool empty()
const {
return size_ == 0; }
378 [[nodiscard]]
Deallocator* deallocator()
const {
return deallocator_; }
381 PW_ASSERT(size_ < capacity_);
386 PW_ASSERT(size_ != 0);
392 : deallocator_(&alloc), capacity_(capacity) {}
395 uint16_t capacity_ = 0;
406 std::lock_guard guard(*
this);
407 if (is_open_locked()) {
416 std::lock_guard guard(*
this);
417 if (is_open_locked()) {
424 template <
typename U,
425 int&... kExplicitGuard,
426 std::enable_if_t<std::is_same_v<::cpp20::remove_cvref_t<U>, T>,
429 deque_.push_back(std::forward<U>(value));
433 template <
typename U,
434 int&... kExplicitGuard,
435 std::enable_if_t<!std::is_same_v<::cpp20::remove_cvref_t<U>, T> &&
436 std::is_constructible_v<T, U>,
439 PushAndWake(T(value));
447 template <
typename... Args>
449 deque_.emplace_back(std::forward<Args>(args)...);
454 if constexpr (std::is_void_v<T>) {
458 T value = std::move(deque_.front());
467 return remaining_capacity_locked() == 0;
471 std::lock_guard guard(*
this);
472 return remaining_capacity_locked();
475 uint16_t remaining_capacity_locked()
const
477 return deque_.capacity() - deque_.size() - reservations();
482 return deque_.capacity();
486 return deque_.empty();
489 template <
typename U,
490 int&... kExplicitGuard,
491 std::enable_if_t<std::is_same_v<::cpp20::remove_cvref_t<U>, T>,
494 std::lock_guard guard(*
this);
495 if (!is_open_locked()) {
501 PushAndWake(std::forward<U>(value));
505 template <
typename U,
506 int&... kExplicitGuard,
507 std::enable_if_t<!std::is_same_v<::cpp20::remove_cvref_t<U>, T> &&
508 std::is_constructible_v<T, U>,
511 return TrySend(T(value));
517 "TrySend() with no arguments is for notification channels only");
519 std::lock_guard guard(*
this);
520 if (!is_open_locked()) {
532 std::lock_guard guard(*
this);
533 if (deque_.empty()) {
537 if constexpr (std::is_void_v<T>) {
541 return Result(PopAndWake());
546 std::lock_guard guard(*
this);
547 if (!is_open_locked()) {
557 template <
typename... Args>
560 remove_reservation();
561 if (is_open_locked()) {
562 EmplaceAndWake(std::forward<Args>(args)...);
564 RemoveRefAndDestroyIfUnreferenced();
569 remove_reservation();
570 if (is_open_locked()) {
573 RemoveRefAndDestroyIfUnreferenced();
578 : deque_(std::move(deque)) {}
580 template <
size_t kAlignment,
size_t kCapacity>
588 return deque_.deallocator();
600 if (deque.capacity() == 0) {
613 Deallocator*
const deallocator = this->deallocator();
619template <
typename T, u
int16_t kCapacity>
629template <u
int16_t kCapacity>
652 return channel_ !=
nullptr && channel_->is_open();
670 : channel_(&channel) {
671 channel_->add_handle();
678 : channel_(std::exchange(other.channel_,
nullptr)) {}
680 BaseChannelHandle& operator=(BaseChannelHandle&& other)
noexcept
688 BaseChannel* channel_;
715 PW_ASSERT(channel() !=
nullptr);
722 PW_ASSERT(channel() !=
nullptr);
740 template <
typename U>
744 template <
typename U, u
int16_t kCapacity>
761 template <
typename U>
762 friend std::optional<std::tuple<MpscChannelHandle<U>,
Receiver<U>>>
765 template <
typename U, u
int16_t kCapacity>
782 template <
typename U>
783 friend std::optional<std::tuple<SpmcChannelHandle<U>,
Sender<U>>>
786 template <
typename U, u
int16_t kCapacity>
801 template <
typename U>
805 template <
typename U, u
int16_t kCapacity>
900template <
typename T, u
int16_t kCapacity>
904 template <
typename U, u
int16_t kCap>
908 template <
typename U, u
int16_t kCap>
909 friend std::tuple<MpscChannelHandle<U>,
Receiver<U>> CreateMpscChannel(
912 template <
typename U, u
int16_t kCap>
913 friend std::tuple<SpmcChannelHandle<U>,
Sender<U>> CreateSpmcChannel(
916 template <
typename U, u
int16_t kCap>
925 std::lock_guard lock(*
this);
926 return this->active_locked();
929 constexpr uint16_t capacity()
const {
return kCapacity; }
943 :
Base(std::move(other)) {}
948 return static_cast<ReceiveFuture&
>(this->MoveAssignFrom(other));
952 this->RemoveFromChannel();
962 template <
typename,
typename>
967 :
Base(channel, this->kAllowClosed) {}
970 if (this->channel() ==
nullptr) {
971 PW_DASSERT(this->is_pendable());
972 return Ready<std::optional<T>>(std::nullopt);
975 this->channel()->lock();
976 PW_DASSERT(this->is_pendable());
977 if (this->channel()->empty()) {
978 return this->StoreWakerForReceiveIfOpen(cx)
980 : Ready<std::optional<T>>(std::nullopt);
983 auto result =
Ready(this->channel()->PopAndWake());
1000 :
Base(std::move(other)) {}
1005 return static_cast<ReceiveFuture&
>(this->MoveAssignFrom(other));
1009 this->RemoveFromChannel();
1019 template <
typename,
typename>
1024 :
Base(channel, this->kAllowClosed) {}
1027 if (this->channel() ==
nullptr) {
1028 PW_DASSERT(this->is_pendable());
1029 return Ready(
false);
1032 this->channel()->lock();
1033 PW_DASSERT(this->is_pendable());
1034 if (this->channel()->empty()) {
1035 return this->StoreWakerForReceiveIfOpen(cx) ?
Pending() :
Ready(
false);
1038 this->channel()->PopAndWake();
1045template <
typename T>
1048 constexpr Receiver() : channel_(
nullptr) {}
1054 : channel_(std::exchange(other.channel_,
nullptr)) {}
1057 if (
this == &other) {
1060 if (channel_ !=
nullptr) {
1061 channel_->remove_receiver();
1063 channel_ = std::exchange(other.channel_,
nullptr);
1068 if (channel_ !=
nullptr) {
1069 channel_->remove_receiver();
1086 if (channel_ ==
nullptr) {
1091 if constexpr (std::is_void_v<T>) {
1092 if (
Status result = channel_->TryReceive();
1093 result.ok() || result.IsFailedPrecondition()) {
1097 if (
Result<T> result = channel_->TryReceive();
1098 result.ok() || result.status().IsFailedPrecondition()) {
1104 std::conditional_t<std::is_void_v<T>, bool, std::optional<T>>;
1110 [&result, ¬ification](ReceiveType&& val) {
1111 result = std::move(val);
1115 dispatcher.Post(task);
1119 if constexpr (std::is_void_v<T>) {
1122 if (!result.has_value()) {
1133 if constexpr (std::is_void_v<T>) {
1136 if (!result.has_value()) {
1161 if (channel_ ==
nullptr) {
1165 return channel_->TryReceive();
1173 if (channel_ !=
nullptr) {
1174 channel_->remove_receiver();
1181 return channel_ !=
nullptr && channel_->is_open();
1185 template <
typename U>
1188 template <
typename U>
1189 friend std::optional<std::tuple<MpscChannelHandle<U>,
Receiver<U>>>
1192 template <
typename U, u
int16_t kCapacity>
1196 template <
typename U>
1200 template <
typename U, u
int16_t kCapacity>
1206 : channel_(&channel) {
1207 channel_->add_receiver();
1210 internal::Channel<T>* channel_;
1213template <
typename T>
1223 :
Base(
static_cast<Base&&
>(other)), value_(std::move(other.value_)) {}
1227 value_ = std::move(other.value_);
1229 return static_cast<SendFuture&
>(this->MoveAssignFrom(other));
1233 this->RemoveFromChannel();
1246 :
Base(channel), value_(value) {}
1250 :
Base(channel), value_(std::move(value)) {}
1253 if (this->channel() ==
nullptr) {
1254 PW_DASSERT(this->is_pendable());
1255 return Ready(
false);
1258 this->channel()->lock();
1259 PW_DASSERT(this->is_pendable());
1260 if (!this->channel()->is_open_locked()) {
1262 return Ready(
false);
1265 if (this->channel()->full()) {
1266 this->StoreWakerForSend(cx);
1270 this->channel()->PushAndWake(std::move(*value_));
1275 std::optional<T> value_;
1288 :
Base(
static_cast<Base&&
>(other)) {}
1293 return static_cast<SendFuture&
>(this->MoveAssignFrom(other));
1297 this->RemoveFromChannel();
1313 if (this->channel() ==
nullptr) {
1314 PW_DASSERT(this->is_pendable());
1315 return Ready(
false);
1318 this->channel()->lock();
1319 PW_DASSERT(this->is_pendable());
1320 if (!this->channel()->is_open_locked()) {
1322 return Ready(
false);
1325 if (this->channel()->full()) {
1326 this->StoreWakerForSend(cx);
1330 this->channel()->PushAndWake();
1342template <
typename T>
1349 : channel_(std::exchange(other.channel_,
nullptr)) {}
1352 if (
this == &other) {
1356 channel_ = std::exchange(other.channel_,
nullptr);
1363 template <
typename... Args>
1365 PW_ASSERT(channel_ !=
nullptr);
1366 channel_->CommitReservationAndRemoveRef(std::forward<Args>(args)...);
1370 void CommitNotification() {
1371 static_assert(std::is_void_v<T>,
1372 "CommitNotification() is for notification channels only.");
1373 PW_ASSERT(channel_ !=
nullptr);
1374 channel_->CommitNotificationReservationAndRemoveRef();
1380 if (channel_ !=
nullptr) {
1381 channel_->DropReservationAndRemoveRef();
1396 : channel_(&channel) {
1397 channel_->add_ref();
1400 internal::Channel<T>* channel_;
1403template <
typename T>
1407 std::optional<SendReservation<T>>> {
1409 using Base = internal::
1410 ChannelFuture<ReserveSendFuture, T, std::optional<SendReservation<T>>>;
1423 this->RemoveFromChannel();
1440 if (this->channel() ==
nullptr) {
1441 PW_DASSERT(this->is_pendable());
1442 return Ready<std::optional<SendReservation<T>>>(std::nullopt);
1445 this->channel()->lock();
1446 PW_DASSERT(this->is_pendable());
1447 if (!this->channel()->is_open_locked()) {
1449 return Ready<std::optional<SendReservation<T>>>(std::nullopt);
1452 if (this->channel()->remaining_capacity_locked() == 0) {
1453 this->StoreWakerForReserveSend(cx);
1457 this->channel()->add_reservation();
1465template <
typename T>
1468 constexpr Sender() : channel_(
nullptr) {}
1474 : channel_(std::exchange(other.channel_,
nullptr)) {}
1477 if (
this == &other) {
1480 if (channel_ !=
nullptr) {
1481 channel_->remove_sender();
1483 channel_ = std::exchange(other.channel_,
nullptr);
1488 if (channel_ !=
nullptr) {
1489 channel_->remove_sender();
1501 template <
typename U>
1507 static_assert(std::is_void_v<T>,
1508 "Send() with no arguments is for notification channels only");
1529 if (channel_ ==
nullptr) {
1532 return channel_->TryReserveSend();
1544 template <
typename U,
1545 int&... kExplicitGuard,
1546 std::enable_if_t<std::is_same_v<::cpp20::remove_cvref_t<U>, T>,
1549 if (channel_ ==
nullptr) {
1552 return channel_->TrySend(std::forward<U>(value));
1556 template <
typename U,
1557 int&... kExplicitGuard,
1558 std::enable_if_t<!std::is_same_v<::cpp20::remove_cvref_t<U>, T> &&
1559 std::is_constructible_v<T, U>,
1578 "TrySend() with no arguments is for notification channels only");
1579 if (channel_ ==
nullptr) {
1582 return channel_->TrySend();
1595 template <
typename U,
1596 int&... kExplicitGuard,
1597 std::enable_if_t<std::is_same_v<::cpp20::remove_cvref_t<U>, T>,
1603 return BlockingSendMoveOrCopy(dispatcher, std::forward<U>(value), timeout);
1607 template <
typename U,
1608 int&... kExplicitGuard,
1609 std::enable_if_t<!std::is_same_v<::cpp20::remove_cvref_t<U>, T> &&
1610 std::is_constructible_v<T, U>,
1616 return BlockingSendMoveOrCopy(dispatcher, T(value), timeout);
1632 return BlockingSendMoveOrCopy(dispatcher, timeout);
1640 if (channel_ !=
nullptr) {
1641 channel_->remove_sender();
1648 return channel_ !=
nullptr ? channel_->remaining_capacity() : 0;
1653 return channel_ !=
nullptr ? channel_->capacity() : 0;
1658 return channel_ !=
nullptr && channel_->is_open();
1662 template <
typename U>
1665 template <
typename U>
1666 friend std::optional<std::tuple<SpmcChannelHandle<U>,
Sender<U>>>
1669 template <
typename U, u
int16_t kCapacity>
1673 template <
typename U>
1677 template <
typename U, u
int16_t kCapacity>
1683 : channel_(&channel) {
1684 channel_->add_sender();
1687 template <
typename U>
1688 Status BlockingSendMoveOrCopy(Dispatcher& dispatcher,
1692 if (channel_ ==
nullptr) {
1696 if (Status status = channel_->TrySend(std::forward<U>(value));
1697 status.ok() || status.IsFailedPrecondition()) {
1701 return BlockingSendFuture(
1703 SendFuture<T>(channel_, std::forward<U>(value)),
1707 Status BlockingSendMoveOrCopy(Dispatcher& dispatcher,
1710 if (channel_ ==
nullptr) {
1714 if (Status status = channel_->TrySend();
1715 status.ok() || status.IsFailedPrecondition()) {
1719 return BlockingSendFuture(dispatcher, SendFuture<T>(channel_), timeout);
1722 Status BlockingSendFuture(Dispatcher& dispatcher,
1723 SendFuture<T>&& future,
1727 sync::TimedThreadNotification notification;
1730 [&status, ¬ification](
bool result) {
1731 status = result ?
OkStatus() : Status::FailedPrecondition();
1732 notification.release();
1735 dispatcher.Post(task);
1737 if (timeout == internal::Channel<T>::kWaitForever) {
1738 notification.acquire();
1742 if (!notification.try_acquire_for(timeout)) {
1749 internal::Channel<T>* channel_;
1765template <
typename T>
1767 uint16_t capacity) {
1769 if (channel ==
nullptr) {
1770 return std::nullopt;
1772 std::lock_guard lock(*channel);
1787template <
typename T, u
int16_t kCapacity>
1790 PW_DASSERT(!storage.active_locked());
1807template <
typename T>
1811 if (channel ==
nullptr) {
1812 return std::nullopt;
1814 std::lock_guard lock(*channel);
1829template <
typename T, u
int16_t kCapacity>
1833 PW_DASSERT(!storage.active_locked());
1850template <
typename T>
1854 if (channel ==
nullptr) {
1855 return std::nullopt;
1857 std::lock_guard lock(*channel);
1872template <
typename T, u
int16_t kCapacity>
1876 PW_DASSERT(!storage.active_locked());
1893template <
typename T>
1894std::optional<std::tuple<SpscChannelHandle<T>, Sender<T>, Receiver<T>>>
1897 if (channel ==
nullptr) {
1898 return std::nullopt;
1900 std::lock_guard lock(*channel);
1917template <
typename T, u
int16_t kCapacity>
1921 PW_DASSERT(!storage.active_locked());
1922 return std::make_tuple(
1931 channel_->RemoveRefAndDestroyIfUnreferenced();
Definition: allocator.h:42
T * New(Args &&... args)
Definition: allocator.h:66
Abstract interface for releasing memory.
Definition: deallocator.h:30
void Deallocate(void *ptr)
Definition: deallocator.h:316
static constexpr Status DeadlineExceeded()
Definition: status.h:177
static constexpr Status Unavailable()
Definition: status.h:304
static constexpr Status FailedPrecondition()
Definition: status.h:243
Definition: callback_task.h:44
Channel handle for a particular type T.
Definition: channel.h:697
Sender< T > CreateSender()
Definition: channel.h:714
Receiver< T > CreateReceiver()
Definition: channel.h:721
Definition: channel.h:902
bool active() const
Definition: channel.h:924
Definition: dispatcher.h:74
constexpr bool is_pendable() const
Definition: future.h:255
void MarkComplete()
Definition: future.h:306
constexpr bool is_complete() const
Definition: future.h:260
Definition: channel.h:857
Definition: channel.h:814
A handle to a multi-producer, multi-consumer channel.
Definition: channel.h:729
friend std::optional< MpmcChannelHandle< U > > CreateMpmcChannel(Allocator &, uint16_t)
Definition: channel.h:1766
A handle to a multi-producer, single-consumer channel.
Definition: channel.h:751
friend std::optional< std::tuple< MpscChannelHandle< U >, Receiver< U > > > CreateMpscChannel(Allocator &, uint16_t)
Definition: channel.h:1808
constexpr bool IsReady() const noexcept
Returns whether or not this value is Ready.
Definition: poll.h:211
Definition: channel.h:934
A receiver which reads values from an asynchronous channel.
Definition: channel.h:1046
friend std::optional< std::tuple< MpscChannelHandle< U >, Receiver< U > > > CreateMpscChannel(Allocator &, uint16_t)
Definition: channel.h:1808
bool is_open() const
Returns true if the channel is open.
Definition: channel.h:1180
std::conditional_t< std::is_void_v< T >, Status, Result< T > > TryReceive()
Definition: channel.h:1160
friend std::optional< std::tuple< SpscChannelHandle< U >, Sender< U >, Receiver< U > > > CreateSpscChannel(Allocator &, uint16_t)
Definition: channel.h:1895
void Disconnect()
Definition: channel.h:1172
std::conditional_t< std::is_void_v< T >, Status, Result< T > > BlockingReceive(Dispatcher &dispatcher, chrono::SystemClock::duration timeout=internal::Channel< T >::kWaitForever)
Definition: channel.h:1082
ReceiveFuture< T > Receive()
Definition: channel.h:1150
Definition: channel.h:1407
Definition: channel.h:1215
Definition: channel.h:1343
void Cancel()
Releases the reservation, making the space available for other senders.
Definition: channel.h:1379
void Commit(Args &&... args)
Commits a value to a reserved slot.
Definition: channel.h:1364
A sender which writes values to an asynchronous channel.
Definition: channel.h:1466
SendFuture< T > Send(U &&value)
Definition: channel.h:1502
Status TrySend(U &&value)
Definition: channel.h:1548
Result< SendReservation< T > > TryReserveSend()
Definition: channel.h:1528
friend std::optional< std::tuple< SpmcChannelHandle< U >, Sender< U > > > CreateSpmcChannel(Allocator &, uint16_t)
Definition: channel.h:1851
friend std::optional< std::tuple< SpscChannelHandle< U >, Sender< U >, Receiver< U > > > CreateSpscChannel(Allocator &, uint16_t)
Definition: channel.h:1895
ReserveSendFuture< T > ReserveSend()
Definition: channel.h:1517
uint16_t capacity() const
Returns the maximum capacity of the channel.
Definition: channel.h:1652
Status BlockingSend(Dispatcher &dispatcher, chrono::SystemClock::duration timeout=internal::Channel< T >::kWaitForever)
Definition: channel.h:1629
Status BlockingSend(Dispatcher &dispatcher, U &&value, chrono::SystemClock::duration timeout=internal::Channel< T >::kWaitForever)
Definition: channel.h:1599
uint16_t remaining_capacity() const
Returns the remaining capacity of the channel.
Definition: channel.h:1647
void Disconnect()
Definition: channel.h:1639
bool is_open() const
Returns true if the channel is open.
Definition: channel.h:1657
Status TrySend()
Definition: channel.h:1575
A handle to a single-producer, multi-consumer channel.
Definition: channel.h:772
friend std::optional< std::tuple< SpmcChannelHandle< U >, Sender< U > > > CreateSpmcChannel(Allocator &, uint16_t)
Definition: channel.h:1851
A handle to a single-producer, single-consumer channel.
Definition: channel.h:793
friend std::optional< std::tuple< SpscChannelHandle< U >, Sender< U >, Receiver< U > > > CreateSpscChannel(Allocator &, uint16_t)
Definition: channel.h:1895
bool is_complete() const
True if the future has returned Ready().
Definition: channel.h:75
bool is_pendable() const
True if the Pend can be called on the future.
Definition: channel.h:72
Definition: channel.h:643
Definition: channel.h:167
Definition: channel.h:621
Definition: channel.h:317
Definition: channel.h:132
Definition: channel.h:402
Definition: channel.h:596
Definition: interrupt_spin_lock.h:50
Definition: timed_thread_notification.h:40
bool try_acquire_for(chrono::SystemClock::duration timeout)
std::optional< std::tuple< SpmcChannelHandle< T >, Sender< T > > > CreateSpmcChannel(Allocator &alloc, uint16_t capacity)
Definition: channel.h:1851
std::optional< std::tuple< MpscChannelHandle< T >, Receiver< T > > > CreateMpscChannel(Allocator &alloc, uint16_t capacity)
Definition: channel.h:1808
std::optional< MpmcChannelHandle< T > > CreateMpmcChannel(Allocator &alloc, uint16_t capacity)
Definition: channel.h:1766
std::optional< std::tuple< SpscChannelHandle< T >, Sender< T >, Receiver< T > > > CreateSpscChannel(Allocator &alloc, uint16_t capacity)
Definition: channel.h:1895
std::conditional_t< std::is_void_v< typename T::value_type >, ReadyType, typename T::value_type > FutureValue
Definition: future.h:110
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
std::chrono::duration< rep, period > duration
Alias for durations representable with this clock.
Definition: system_clock.h:91
constexpr bool CheckedIncrement(T &base, Inc inc)
Definition: checked_arithmetic.h:118
constexpr Status OkStatus()
Definition: status.h:450
#define PW_LOCKABLE(name)
Definition: lock_annotations.h:210
#define PW_GUARDED_BY(x)
Definition: lock_annotations.h:60
#define PW_NO_LOCK_SAFETY_ANALYSIS
Definition: lock_annotations.h:296
#define PW_EXCLUSIVE_LOCK_FUNCTION(...)
Definition: lock_annotations.h:232
#define PW_EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: lock_annotations.h:147
#define PW_LOCK_RETURNED(x)
Definition: lock_annotations.h:199
#define PW_UNLOCK_FUNCTION(...)
Definition: lock_annotations.h:249
#define PW_LOCKS_EXCLUDED(...)
Definition: lock_annotations.h:178