Feature: actor output #1

Merged
erki merged 3 commits from feature/actor_output into master 2021-11-12 21:23:13 +00:00
2 changed files with 130 additions and 0 deletions

View File

@ -51,6 +51,11 @@ public:
: q_(q) : q_(q)
{} {}
Signal(const Signal&) = default;
Signal(Signal&&) = default;
Signal& operator=(const Signal&) = default;
Signal& operator=(Signal&&) = default;
void emit(const T& data) override void emit(const T& data) override
{ {
parent::value_type to_send = data; parent::value_type to_send = data;
@ -79,6 +84,14 @@ public:
return Signal<U>(this); return Signal<U>(this);
} }
template<typename U>
Signal<U>* getAllocatedSignal()
{
static_assert(std::is_convertible_v<U, value_type>, "value_type cannot be constructed from U.");
return new Signal<U>(this);
}
Signallable<value_type>* getStaticSignal() Signallable<value_type>* getStaticSignal()
{ {
return &signal_; return &signal_;

View File

@ -0,0 +1,117 @@
/*
* threads_actor_output.hpp
*
* Created on: Oct 24, 2021
* Author: erki
*/
#ifndef SKULLC_THREADS_ACTOR_OUTPUT_HPP_
#define SKULLC_THREADS_ACTOR_OUTPUT_HPP_
#include <array>
#include <optional>
#include <variant>
#include <threads_signal.hpp>
namespace Threads
{
template<std::size_t N, typename... Ts>
class ActorOutput
{
private:
using signal_variant = std::variant<std::monostate, Signallable<Ts>*...>;
std::array<signal_variant, N> stored_signals_;
public:
ActorOutput() = default;
ActorOutput(const ActorOutput&) = delete;
ActorOutput(ActorOutput&&) = delete;
ActorOutput& operator=(const ActorOutput&) = delete;
ActorOutput& operator=(ActorOutput&&) = delete;
using connection_type = std::optional<typename decltype(stored_signals_)::iterator>;
template<typename T>
connection_type addConnection(Signallable<T>* signal)
{
static_assert(std::disjunction_v<std::is_same<T, Ts>...>, "T is not a member of Ts.");
for (auto it = stored_signals_.begin(); it != stored_signals_.end(); ++it)
{
auto& storage = *it;
if (std::get_if<std::monostate>(&storage))
{
storage = signal_variant{signal};
return it;
}
}
return std::nullopt;
}
bool removeConnection(connection_type& connection)
{
if (!connection)
return true;
for (auto it = stored_signals_.begin(); it != stored_signals_.end(); ++it)
{
if (it == *connection)
{
delete *it;
*it = std::monostate{};
return true;
}
}
return false;
}
protected:
template<typename T>
void emitOutput(const T& data)
{
static_assert(std::disjunction_v<std::is_same<T, Ts>...>, "T is not a member of Ts.");
for (auto& s : stored_signals_)
{
if (auto** signal = std::get_if<Signallable<T>*>(&s))
(*signal)->emit(data);
}
}
template<typename T>
void emitOutputFromIsr(const T& data)
{
static_assert(std::disjunction_v<std::is_same<T, Ts>...>, "T is not a member of Ts.");
for (auto& s : stored_signals_)
{
if (auto** signal = std::get_if<Signallable<T>*>(&s))
(*signal)->emitFromIsr(data);
}
}
};
template<typename T, typename Sender, typename Receiver>
auto connectActors(Sender* sender, Receiver* receiver)
{
auto* signal = receiver->template getAllocatedSignal<T>();
return sender->addConnection(signal);
}
template<typename T, typename Sender, typename Receiver>
auto connectActors(Sender& sender, Receiver& receiver)
{
auto* signal = receiver.template getAllocatedSignal<T>();
return sender.addConnection(signal);
}
}// namespace Threads
#endif// SKULLC_THREADS_ACTOR_OUTPUT_HPP_