/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #ifndef __SIGNAL__ #define __SIGNAL__ #include "container/nlist.h" namespace GS { // template class Signal { /// Base signal listener. struct IListener { virtual void Call(T) = 0; virtual bool BelongsToInstance(void *) const = 0; virtual bool IsFunction(void (*)(T)) const = 0; virtual ~IListener() {} }; AutoList listeners; /// Pointer to member listener. template struct InstanceListener : public IListener { O *i; void (O::*f)(T1); void Call(T1 t) { (i->*f)(t); } bool BelongsToInstance(void *p) const { return asbool(p == (void *)i); } bool IsFunction(void (*)(T1)) const { return false; } InstanceListener(O *_i, void (O::*_f)(T1)) : i(_i), f(_f) {} }; /// Global/static function listener. template struct FunctionListener : public IListener { void (*f)(T1); void Call(T1 t) { (*f)(t); } bool BelongsToInstance(void *) const { return false; } bool IsFunction(void (*_f)(T1)) const { return f == _f; } FunctionListener(void (*_f)(T1)) : f(_f) {} }; public: /// Return the number of listener on this signal. uint GetListenerCount() const { return listeners.GetCount(); } /// Subscribe an instance member function to call when the event is triggered. template void Connect(O *i, void (O::*f)(T)) { listeners.Add(new InstanceListener (i, f)); } /// Remove the subscription of all handlers associated with a specific class instance. template void Disconnect(O *i) { ListForeachPtr(IListener *, l, this->listeners) if (l->BelongsToInstance((void *)i)) listeners.Remove(l); } /// Subscribe a function to call when the event is triggered. void Connect(void (*f)(T)) { listeners.Add(new FunctionListener (f)); } /// Remove a function subscription. void Disconnect(void (*f)(T)) { ListForeachPtr(IListener *, l, this->listeners) if (l->IsFunction(f)) listeners.Remove(l); } /// Emit the signal, notifies all listeners. void Emit(T t) const { ListForeachPtr(IListener *, l, listeners) l->Call(t); } }; // Specialization for void type. Note: I gave up on factoring code => compiler vendor/extension hell. template <> class Signal { /// Base signal listener. struct IListener { virtual void Call() = 0; virtual bool BelongsToInstance(void *) const = 0; virtual bool IsFunction(void (*)()) const = 0; virtual ~IListener() {} }; AutoList listeners; /// Pointer to member listener. template struct InstanceListener : public IListener { O *i; void (O::*f)(); void Call() { (i->*f)(); } bool BelongsToInstance(void *p) const { return asbool(p == (void *)i); } bool IsFunction(void (*)()) const { return false; } InstanceListener(O *_i, void (O::*_f)()) : i(_i), f(_f) {} }; /// Global/static function listener. struct FunctionListener : public IListener { void (*f)(); void Call() { (*f)(); } bool BelongsToInstance(void *) const { return false; } bool IsFunction(void (*_f)()) const { return f == _f; } FunctionListener(void (*_f)()) : f(_f) {} }; public: /// Return the number of listener on this signal. uint GetListenerCount() const { return listeners.GetCount(); } /// Subscribe an instance member function to call when the event is triggered. template void Connect(O *i, void (O::*f)()) { listeners.Add(new InstanceListener (i, f)); } /// Remove the subscription of all handlers associated with a specific class instance. template void Disconnect(O *i) { ListForeachPtr(IListener *, l, listeners) if (l->BelongsToInstance((void *)i)) listeners.Remove(l); } /// Subscribe a function to call when the event is triggered. void Connect(void (*f)()) { listeners.Add(new FunctionListener(f)); } /// Remove a function subscription. void Disconnect(void (*f)()) { ListForeachPtr(IListener *, l, listeners) if (l->IsFunction(f)) listeners.Remove(l); } /// Emit the signal, notifies all listeners. void Emit() const { ListForeachPtr(IListener *, l, listeners) l->Call(); } }; } // GS #endif // __SIGNAL__