#ifndef CANVAS_SIGNAL_HPP #define CANVAS_SIGNAL_HPP #include "callable.hpp" #include <cstdio> #include <vector> namespace ce { /*! Observer-listener implementation */ template <class... Args> class Signal { std::vector<Callable<void, Args...>> listeners{}; public: void connect(Callable<void, Args...> callable); void disconnect(Callable<void, Args...> callable); void invoke(Args...); }; template <class... Args> void Signal<Args...>::connect(Callable<void, Args...> callable) { this->listeners.push_back(callable); } template <class... Args> void Signal<Args...>::disconnect(Callable<void, Args...> callable) { std::erase_if(this->listeners, [&callable](Callable<void, Args...> &listener) -> bool { return listener == callable; }); } template <class... Args> void Signal<Args...>::invoke(Args... args) { for(Callable<void, Args...> &listener : this->listeners) { listener.call(args...); } } #ifdef DEBUG static inline void TEST_signals() { struct A {inline void f(int val) { std::printf("A: %d\n", val); }}; struct B { inline void f(int val) { std::printf("B: %d\n", val); }}; A a_object; B b_object; Signal<int> signal; Callable<void, int> a_callable{Callable<void, int>::make(&a_object, &A::f)}; Callable<void, int> b_callable{Callable<void, int>::make(&b_object, &B::f)}; signal.connect(a_callable); signal.invoke(5); signal.connect(b_callable); signal.invoke(12); signal.disconnect(a_callable); signal.invoke(10); } #endif } #endif // !CANVAS_SIGNAL_HPP