From 806416e943ab6baa1a51b93a3d028e46ca219920 Mon Sep 17 00:00:00 2001 From: erki Date: Fri, 12 Nov 2021 21:23:12 +0000 Subject: [PATCH] Feature: actor output (#1) Co-authored-by: Erki Reviewed-on: https://git.skullnet.me/erki/skullc-peripherals/pulls/1 Co-authored-by: erki Co-committed-by: erki --- Threads/Inc/threads_actor.hpp | 13 +++ Threads/Inc/threads_actor_output.hpp | 117 +++++++++++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 Threads/Inc/threads_actor_output.hpp diff --git a/Threads/Inc/threads_actor.hpp b/Threads/Inc/threads_actor.hpp index 607615a..41037a1 100644 --- a/Threads/Inc/threads_actor.hpp +++ b/Threads/Inc/threads_actor.hpp @@ -51,6 +51,11 @@ public: : q_(q) {} + Signal(const Signal&) = default; + Signal(Signal&&) = default; + Signal& operator=(const Signal&) = default; + Signal& operator=(Signal&&) = default; + void emit(const T& data) override { parent::value_type to_send = data; @@ -79,6 +84,14 @@ public: return Signal(this); } + template + Signal* getAllocatedSignal() + { + static_assert(std::is_convertible_v, "value_type cannot be constructed from U."); + + return new Signal(this); + } + Signallable* getStaticSignal() { return &signal_; diff --git a/Threads/Inc/threads_actor_output.hpp b/Threads/Inc/threads_actor_output.hpp new file mode 100644 index 0000000..748a3e2 --- /dev/null +++ b/Threads/Inc/threads_actor_output.hpp @@ -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 +#include +#include + +#include + +namespace Threads +{ + +template +class ActorOutput +{ +private: + using signal_variant = std::variant*...>; + std::array 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; + + template + connection_type addConnection(Signallable* signal) + { + static_assert(std::disjunction_v...>, "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(&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 + void emitOutput(const T& data) + { + static_assert(std::disjunction_v...>, "T is not a member of Ts."); + + for (auto& s : stored_signals_) + { + if (auto** signal = std::get_if*>(&s)) + (*signal)->emit(data); + } + } + + template + void emitOutputFromIsr(const T& data) + { + static_assert(std::disjunction_v...>, "T is not a member of Ts."); + + for (auto& s : stored_signals_) + { + if (auto** signal = std::get_if*>(&s)) + (*signal)->emitFromIsr(data); + } + } +}; + +template +auto connectActors(Sender* sender, Receiver* receiver) +{ + auto* signal = receiver->template getAllocatedSignal(); + return sender->addConnection(signal); +} + +template +auto connectActors(Sender& sender, Receiver& receiver) +{ + auto* signal = receiver.template getAllocatedSignal(); + return sender.addConnection(signal); +} + +}// namespace Threads + +#endif// SKULLC_THREADS_ACTOR_OUTPUT_HPP_