22template <
typename T,
size_t Capacity = 16>
24 static_assert(Capacity > 0,
"Channel capacity must be greater than zero.");
42 if (m_closed.load(std::memory_order_acquire)) {
46 size_t count = m_count.load(std::memory_order_relaxed);
47 if (count >= Capacity) {
51 size_t tail = m_tail.load(std::memory_order_relaxed);
52 m_buffer[tail] = std::move(value);
53 m_tail.store((tail + 1) % Capacity, std::memory_order_relaxed);
54 m_count.fetch_add(1, std::memory_order_release);
57 auto h = m_recvWaiter.exchange(
nullptr, std::memory_order_acq_rel);
68 size_t count = m_count.load(std::memory_order_relaxed);
73 size_t head = m_head.load(std::memory_order_relaxed);
74 out = std::move(m_buffer[head]);
75 m_head.store((head + 1) % Capacity, std::memory_order_relaxed);
76 m_count.fetch_sub(1, std::memory_order_release);
79 auto h = m_sendWaiter.exchange(
nullptr, std::memory_order_acq_rel);
88 m_closed.store(
true, std::memory_order_release);
89 auto hr = m_recvWaiter.exchange(
nullptr, std::memory_order_acq_rel);
90 if (hr && !hr.done()) {
93 auto hs = m_sendWaiter.exchange(
nullptr, std::memory_order_acq_rel);
94 if (hs && !hs.done()) {
101 return m_closed.load(std::memory_order_acquire);
105 [[nodiscard]]
size_t size() const noexcept {
106 return m_count.load(std::memory_order_relaxed);
110 [[nodiscard]]
bool empty() const noexcept {
115 [[nodiscard]]
bool full() const noexcept {
116 return size() >= Capacity;
138 chan.m_pendingPushVal = std::move(
val);
139 chan.m_sendWaiter.store(h, std::memory_order_release);
145 if (
chan.m_pendingPushVal.has_value()) {
147 chan.m_pendingPushVal.reset();
189 chan.m_recvWaiter.store(h, std::memory_order_release);
212 std::array<T, Capacity> m_buffer{};
213 std::atomic<size_t> m_head{0};
214 std::atomic<size_t> m_tail{0};
215 std::atomic<size_t> m_count{0};
216 std::atomic<bool> m_closed{
false};
218 std::atomic<std::coroutine_handle<>> m_recvWaiter{
nullptr};
219 std::atomic<std::coroutine_handle<>> m_sendWaiter{
nullptr};
220 std::optional<T> m_pendingPushVal{};
Statically allocated bounded asynchronous channel for typed producer-consumer coroutines.
Definition Channel.hpp:23
Channel & operator=(const Channel &)=delete
bool full() const noexcept
Check if channel is full.
Definition Channel.hpp:115
void close() noexcept
Close the channel. No more pushes will succeed. Remaining elements can still be popped.
Definition Channel.hpp:87
PushAwaiter push(T val) noexcept
Push an item into the channel asynchronously with backpressure suspension.
Definition Channel.hpp:157
constexpr Channel() noexcept=default
size_t size() const noexcept
Number of elements currently in the channel.
Definition Channel.hpp:105
bool isClosed() const noexcept
Check if channel is closed.
Definition Channel.hpp:100
bool tryPop(T &out) noexcept
Non-blocking attempt to pop an item from the channel.
Definition Channel.hpp:67
T ValueType
Definition Channel.hpp:27
Channel(const Channel &)=delete
bool empty() const noexcept
Check if channel is empty.
Definition Channel.hpp:110
PopAwaiter pop() noexcept
Pop an item from the channel asynchronously.
Definition Channel.hpp:207
bool tryPush(T value) noexcept
Non-blocking attempt to push an item into the channel.
Definition Channel.hpp:41
Definition AsyncEvent.hpp:14
Awaiter for popping an item asynchronously (suspends if channel is empty).
Definition Channel.hpp:162
Channel & chan
Definition Channel.hpp:163
bool await_suspend(std::coroutine_handle<> h) noexcept
Definition Channel.hpp:179
bool await_ready() noexcept
Definition Channel.hpp:166
std::optional< T > await_resume() noexcept
Definition Channel.hpp:193
std::optional< T > result
Definition Channel.hpp:164
Awaiter for pushing an item asynchronously (suspends if channel is full).
Definition Channel.hpp:120
bool await_ready() noexcept
Definition Channel.hpp:125
T val
Definition Channel.hpp:122
Channel & chan
Definition Channel.hpp:121
bool await_resume() noexcept
Definition Channel.hpp:143
bool await_suspend(std::coroutine_handle<> h) noexcept
Definition Channel.hpp:137
bool done
Definition Channel.hpp:123