Rewrote Frontend

This commit is contained in:
2022-09-03 23:32:20 +02:00
parent 0939525cf3
commit 16876e090d
98 changed files with 4995 additions and 1757 deletions

View File

@@ -0,0 +1,68 @@
// Copyright (C) 2022 Andrei Avram
#ifndef MSD_CHANNEL_BLOCKING_ITERATOR_HPP_
#define MSD_CHANNEL_BLOCKING_ITERATOR_HPP_
#include <iterator>
#include <mutex>
namespace msd {
/**
* @brief An iterator that block the current thread,
* waiting to fetch elements from the channel.
*
* Used to implement channel range-based for loop.
*
* @tparam Channel Instance of channel.
*/
template <typename channel>
class blocking_iterator {
public:
using value_type = typename channel::value_type;
explicit blocking_iterator(channel& ch) : ch_{ch} {}
/**
* Advances to next element in the channel.
*/
blocking_iterator<channel> operator++() const noexcept { return *this; }
/**
* Returns an element from the channel.
*/
value_type operator*() const
{
value_type value;
value << ch_;
return value;
}
/**
* Makes iteration continue until the channel is closed and empty.
*/
bool operator!=(blocking_iterator<channel>) const
{
std::unique_lock<std::mutex> lock{ch_.mtx_};
ch_.waitBeforeRead(lock);
return !(ch_.closed() && ch_.empty());
}
private:
channel& ch_;
};
} // namespace msd
/**
* @brief Output iterator specialization
*/
template <typename T>
struct std::iterator_traits<msd::blocking_iterator<T>> {
using value_type = typename msd::blocking_iterator<T>::value_type;
using iterator_category = std::output_iterator_tag;
};
#endif // MSD_CHANNEL_BLOCKING_ITERATOR_HPP_

130
backend/shl/msd/channel.hpp Normal file
View File

@@ -0,0 +1,130 @@
// Copyright (C) 2022 Andrei Avram
#ifndef MSD_CHANNEL_HPP_
#define MSD_CHANNEL_HPP_
#include <atomic>
#include <condition_variable>
#include <cstdlib>
#include <mutex>
#include <queue>
#include <stdexcept>
#include <type_traits>
#include <utility>
#include "blocking_iterator.hpp"
namespace msd {
#if (__cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L))
#define NODISCARD [[nodiscard]]
#else
#define NODISCARD
#endif
namespace detail {
template <typename T>
struct remove_cvref {
using type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
};
template <typename T>
using remove_cvref_t = typename remove_cvref<T>::type;
} // namespace detail
/**
* @brief Exception thrown if trying to write on closed channel.
*/
class closed_channel : public std::runtime_error {
public:
explicit closed_channel(const char* msg) : std::runtime_error{msg} {}
};
/**
* @brief Thread-safe container for sharing data between threads.
*
* Implements a blocking input iterator.
*
* @tparam T The type of the elements.
*/
template <typename T>
class channel {
public:
using value_type = T;
using iterator = blocking_iterator<channel<T>>;
using size_type = std::size_t;
/**
* Creates a new channel.
*
* @param capacity Number of elements the channel can store before blocking.
*/
explicit constexpr channel(size_type capacity = 0);
/**
* Pushes an element into the channel.
*
* @throws closed_channel if channel is closed.
*/
template <typename Type>
friend void operator>>(Type&&, channel<detail::remove_cvref_t<Type>>&);
/**
* Pops an element from the channel.
*
* @tparam Type The type of the elements
*/
template <typename Type>
friend void operator<<(Type&, channel<Type>&);
/**
* Returns the number of elements in the channel.
*/
NODISCARD inline size_type constexpr size() const noexcept;
/**
* Returns true if there are no elements in channel.
*/
NODISCARD inline bool constexpr empty() const noexcept;
/**
* Closes the channel.
*/
inline void close() noexcept;
/**
* Returns true if the channel is closed.
*/
NODISCARD inline bool closed() const noexcept;
/**
* Iterator
*/
iterator begin() noexcept;
iterator end() noexcept;
/**
* Channel cannot be copied or moved.
*/
channel(const channel&) = delete;
channel& operator=(const channel&) = delete;
channel(channel&&) = delete;
channel& operator=(channel&&) = delete;
virtual ~channel() = default;
private:
const size_type cap_;
std::queue<T> queue_;
std::mutex mtx_;
std::condition_variable cnd_;
std::atomic<bool> is_closed_{false};
inline void waitBeforeRead(std::unique_lock<std::mutex>&);
friend class blocking_iterator<channel>;
};
#include "channel_impl.hpp"
} // namespace msd
#endif // MSD_CHANNEL_HPP_

View File

@@ -0,0 +1,87 @@
// Copyright (C) 2022 Andrei Avram
template <typename T>
constexpr channel<T>::channel(const size_type capacity) : cap_{capacity}
{
}
template <typename T>
void operator>>(T&& in, channel<detail::remove_cvref_t<T>>& ch)
{
if (ch.closed()) {
throw closed_channel{"cannot write on closed channel"};
}
std::unique_lock<std::mutex> lock{ch.mtx_};
if (ch.cap_ > 0 && ch.queue_.size() == ch.cap_) {
ch.cnd_.wait(lock, [&ch]() { return ch.queue_.size() < ch.cap_; });
}
ch.queue_.push(std::forward<T>(in));
ch.cnd_.notify_one();
}
template <typename T>
void operator<<(T& out, channel<T>& ch)
{
if (ch.closed() && ch.empty()) {
return;
}
{
std::unique_lock<std::mutex> lock{ch.mtx_};
ch.waitBeforeRead(lock);
if (ch.queue_.size() > 0) {
out = std::move(ch.queue_.front());
ch.queue_.pop();
}
}
ch.cnd_.notify_one();
}
template <typename T>
constexpr typename channel<T>::size_type channel<T>::size() const noexcept
{
return queue_.size();
}
template <typename T>
constexpr bool channel<T>::empty() const noexcept
{
return queue_.empty();
}
template <typename T>
void channel<T>::close() noexcept
{
is_closed_.store(true);
cnd_.notify_all();
}
template <typename T>
bool channel<T>::closed() const noexcept
{
return is_closed_.load();
}
template <typename T>
blocking_iterator<channel<T>> channel<T>::begin() noexcept
{
return blocking_iterator<channel<T>>{*this};
}
template <typename T>
blocking_iterator<channel<T>> channel<T>::end() noexcept
{
return blocking_iterator<channel<T>>{*this};
}
template <typename T>
void channel<T>::waitBeforeRead(std::unique_lock<std::mutex>& lock)
{
cnd_.wait(lock, [this] { return queue_.size() > 0 || closed(); });
}