Files
2026-06-22 11:49:35 +02:00

176 lines
4.4 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#ifndef __SIGNAL__
#define __SIGNAL__
#include "container/nlist.h"
namespace GS {
//
template <typename T> 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 <IListener *> listeners;
/// Pointer to member listener.
template <class O, typename T1> 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 <typename T1> 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 <class O> void Connect(O *i, void (O::*f)(T))
{ listeners.Add(new InstanceListener <O, T> (i, f)); }
/// Remove the subscription of all handlers associated with a specific class instance.
template <class O> 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 <T> (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 <void>
{
/// Base signal listener.
struct IListener
{
virtual void Call() = 0;
virtual bool BelongsToInstance(void *) const = 0;
virtual bool IsFunction(void (*)()) const = 0;
virtual ~IListener() {}
};
AutoList <IListener *> listeners;
/// Pointer to member listener.
template <class O> 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 <class O> void Connect(O *i, void (O::*f)())
{ listeners.Add(new InstanceListener <O> (i, f)); }
/// Remove the subscription of all handlers associated with a specific class instance.
template <class O> 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__