From d42311356f3dc4b06ec5681b2d8c164c46058ee0 Mon Sep 17 00:00:00 2001 From: Relintai Date: Fri, 4 Feb 2022 08:53:57 +0100 Subject: [PATCH] Added a signal class. --- core/signal.cpp | 107 +++++++++++++++++++++++++++++ core/signal.h | 174 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 281 insertions(+) create mode 100644 core/signal.cpp create mode 100644 core/signal.h diff --git a/core/signal.cpp b/core/signal.cpp new file mode 100644 index 0000000..d558e0a --- /dev/null +++ b/core/signal.cpp @@ -0,0 +1,107 @@ +#include "signal.h" + +void Signal::connect_static(void (*func)(Signal *)) { + StaticSignalEntry *se = new StaticSignalEntry(); + se->func = func; + + entries.push_back(se); +} +void Signal::disconnect_static(void (*func)(Signal *)) { + for (int i = 0; i < entries.size(); ++i) { + SignalEntry *e = entries[i]; + + if (e->type == SIGNAL_ENTRY_TYPE_STATIC) { + StaticSignalEntry *se = static_cast(e); + + if (se->func == func) { + entries.remove_keep_order(i); + return; + } + } + } +} +bool Signal::is_connected_static(void (*func)(Signal *)) { + for (int i = 0; i < entries.size(); ++i) { + SignalEntry *e = entries[i]; + + if (e->type == SIGNAL_ENTRY_TYPE_STATIC) { + StaticSignalEntry *se = static_cast(e); + + if (se->func == func) { + return true; + } + } + } + + return false; +} + +void Signal::emit() { + for (int i = 0; i < entries.size(); ++i) { + entries[i]->call(this); + } +} + +void Signal::emit(const Variant &p1) { + params.push_back(p1); + + for (int i = 0; i < entries.size(); ++i) { + entries[i]->call(this); + } + + params.clear(); +} +void Signal::emit(const Variant &p1, const Variant &p2) { + params.push_back(p1); + params.push_back(p2); + + for (int i = 0; i < entries.size(); ++i) { + entries[i]->call(this); + } + + params.clear(); +} +void Signal::emit(const Variant &p1, const Variant &p2, const Variant &p3) { + params.push_back(p1); + params.push_back(p2); + params.push_back(p3); + + for (int i = 0; i < entries.size(); ++i) { + entries[i]->call(this); + } + + params.clear(); +} + +void Signal::emit(const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4) { + params.push_back(p1); + params.push_back(p2); + params.push_back(p3); + params.push_back(p4); + + for (int i = 0; i < entries.size(); ++i) { + entries[i]->call(this); + } + + params.clear(); +} + +void Signal::emit(const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) { + params.push_back(p1); + params.push_back(p2); + params.push_back(p3); + params.push_back(p4); + params.push_back(p5); + + for (int i = 0; i < entries.size(); ++i) { + entries[i]->call(this); + } + + params.clear(); +} + +Signal::Signal() : + Object() { +} +Signal::~Signal() { +} \ No newline at end of file diff --git a/core/signal.h b/core/signal.h new file mode 100644 index 0000000..643cd65 --- /dev/null +++ b/core/signal.h @@ -0,0 +1,174 @@ +#ifndef SIGNAL_H +#define SIGNAL_H + +#include "core/containers/vector.h" +#include "core/string.h" +#include "core/variant.h" + +#include "reference.h" + +class Signal : public Object { + RCPP_OBJECT(Signal, Object); + +public: + Object *owner; + Vector params; + Vector static_data; + + template + void connect(T *obj, void (*func)(T*, Signal *)); + template + void disconnect(T *obj, void (*func)(T*, Signal *)); + template + bool is_connected(T *obj, void (*func)(T*, Signal *)); + + void connect_static(void (*func)(Signal *)); + void disconnect_static(void (*func)(Signal *)); + bool is_connected_static(void (*func)(Signal *)); + + void emit(); + void emit(const Variant &p1); + void emit(const Variant &p1, const Variant &p2); + void emit(const Variant &p1, const Variant &p2, const Variant &p3); + void emit(const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4); + void emit(const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5); + + Signal(); + ~Signal(); + +protected: + enum SignalEntryType { + SIGNAL_ENTRY_TYPE_NONE = 0, + SIGNAL_ENTRY_TYPE_STATIC = 1, + SIGNAL_ENTRY_TYPE_CLASS = 2, + }; + + struct SignalEntry { + SignalEntryType type; + + virtual void call(Signal *s) { + } + + SignalEntry() { + type = SIGNAL_ENTRY_TYPE_NONE; + } + }; + + struct StaticSignalEntry : public SignalEntry { + void (*func)(Signal *); + + virtual void call(Signal *s) { + func(s); + } + + StaticSignalEntry() { + type = SIGNAL_ENTRY_TYPE_STATIC; + func = nullptr; + } + }; + + struct ClassSignalEntry : public SignalEntry { + + virtual void* get_obj_ptr() { + return nullptr; + } + + virtual void* get_func_ptr() { + return nullptr; + } + + ClassSignalEntry() { + type = SIGNAL_ENTRY_TYPE_CLASS; + } + }; + + template + struct ClassSignalEntrySpec : public ClassSignalEntry { + union { + T* obj; + void* obj_ptr; + }; + union { + void (*func)(T*, Signal *); + void* func_ptr; + }; + + virtual void call(Signal *s) { + func(obj, s); + } + + void* get_obj_ptr() { + return obj_ptr; + } + + void* get_func_ptr() { + return func_ptr; + } + + ClassSignalEntrySpec() { + obj = nullptr; + func = nullptr; + } + }; + +protected: + Vector entries; +}; + +template +void Signal::connect(T *obj, void (*func)(T*, Signal *)) { + ClassSignalEntrySpec *ce = new ClassSignalEntrySpec(); + ce->obj = obj; + ce->func = func; + + entries.push_back(ce); +} + +template +void Signal::disconnect(T *obj, void (*func)(T*, Signal *)) { + ClassSignalEntrySpec t; + t.obj = obj; + t.func = func; + + void* obj_ptr = t.obj_ptr; + void* func_ptr = t.func_ptr; + + for (int i = 0; i < entries.size(); ++i) { + SignalEntry *e = entries[i]; + + if (e->type == SIGNAL_ENTRY_TYPE_CLASS) { + ClassSignalEntry *se = static_cast(e); + + if (se->get_obj_ptr() == obj_ptr && se->get_func_ptr() == func_ptr) { + entries.remove_keep_order(i); + return; + } + } + } +} + +template +bool Signal::is_connected(T *obj, void (*func)(T*, Signal *)) { + ClassSignalEntrySpec t; + t.obj = obj; + t.func = func; + + void* obj_ptr = t.obj_ptr; + void* func_ptr = t.func_ptr; + + for (int i = 0; i < entries.size(); ++i) { + SignalEntry *e = entries[i]; + + if (e->type == SIGNAL_ENTRY_TYPE_CLASS) { + ClassSignalEntry *se = static_cast(e); + + if (se->get_obj_ptr() == obj_ptr && se->get_func_ptr() == func_ptr) { + return true; + } + } + } + + return false; +} + +#endif \ No newline at end of file