176 lines
4.4 KiB
C++
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__
|