3#ifndef MSD_CHANNEL_HPP_
4#define MSD_CHANNEL_HPP_
7#include <condition_variable>
14#include "blocking_iterator.hpp"
18#if (__cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L))
19#define NODISCARD [[nodiscard]]
79 template <
typename Type>
87 template <
typename Type>
103 NODISCARD
bool constexpr empty() const noexcept {
return size_ == 0; }
111 std::unique_lock<std::mutex> lock{mtx_};
112 is_closed_.store(
true, std::memory_order_seq_cst);
123 NODISCARD
bool closed() const noexcept {
return is_closed_.load(std::memory_order_seq_cst); }
150 std::queue<T> queue_;
151 std::atomic<std::size_t> size_{0};
153 std::condition_variable cnd_;
154 std::atomic<bool> is_closed_{
false};
156 void waitBeforeRead(std::unique_lock<std::mutex>& lock)
158 cnd_.wait(lock, [
this]() {
return !
empty() ||
closed(); });
161 void waitBeforeWrite(std::unique_lock<std::mutex>& lock)
163 if (cap_ > 0 && size_ == cap_) {
164 cnd_.wait(lock, [
this]() {
return size_ < cap_; });
168 friend class blocking_iterator<
channel>;
172channel<typename std::decay<T>::type>& operator<<(channel<
typename std::decay<T>::type>& chan, T&& value)
175 std::unique_lock<std::mutex> lock{chan.mtx_};
176 chan.waitBeforeWrite(lock);
179 throw closed_channel{
"cannot write on closed channel"};
182 chan.queue_.push(std::forward<T>(value));
186 chan.cnd_.notify_one();
192channel<T>& operator>>(channel<T>& chan, T& out)
195 std::unique_lock<std::mutex> lock{chan.mtx_};
196 chan.waitBeforeRead(lock);
198 if (chan.closed() && chan.empty()) {
203 out = std::move(chan.queue_.front());
209 chan.cnd_.notify_one();
An iterator that block the current thread, waiting to fetch elements from the channel.
Definition blocking_iterator.hpp:20
Thread-safe container for sharing data between threads.
Definition channel.hpp:45
T value_type
The type of elements stored in the channel.
Definition channel.hpp:50
void close() noexcept
Closes the channel.
Definition channel.hpp:108
friend channel< Type > & operator>>(channel< Type > &, Type &)
Pops an element from the channel.
iterator end() noexcept
Returns an iterator representing the end of the channel.
Definition channel.hpp:137
iterator begin() noexcept
Returns an iterator to the beginning of the channel.
Definition channel.hpp:130
constexpr channel()=default
Creates an unbuffered channel.
NODISCARD bool closed() const noexcept
Checks if the channel has been closed.
Definition channel.hpp:123
NODISCARD bool constexpr empty() const noexcept
Checks if the channel is empty.
Definition channel.hpp:103
channel(const channel &)=delete
std::size_t size_type
The type used to represent sizes and counts.
Definition channel.hpp:60
friend channel< typename std::decay< Type >::type > & operator<<(channel< typename std::decay< Type >::type > &, Type &&)
Pushes an element into the channel.
constexpr channel(const size_type capacity)
Creates a buffered channel.
Definition channel.hpp:72
NODISCARD size_type constexpr size() const noexcept
Returns the current size of the channel.
Definition channel.hpp:95
Exception thrown if trying to write on closed channel.
Definition channel.hpp:27
closed_channel(const char *msg)
Constructs the exception with an error message.
Definition channel.hpp:34