This is a simple and fast implementation of a signal-slot system in C++.
It's goal is to be simple and as fast as possible.
For that, we create a signal-slot system tha is specific for our use case, that's the price we pay for a fast system.
In this case we create callbacks that take an integer value, but it could be adapted for any oyhter use case.
First we need a base class for our callbacks.
We need this class to virtualize the call() function and easily link callbacks in order to create a list.
It is implemented as a linked list: each callbacks holds a pointer to the function to call and a pointer to the next callback.
```c
class CallBackBase
{
public:
CallBackBase(){;}
virtual ~CallBackBase(){;}
virtual void call( int ){;}
CallBackBase* nextCallBack;
};
```
Here we have our callback class.
We create callbacks with an object and a member funtion to call:
```c
template <class Obj>
class CallBack : public CallBackBase
{
friend class Signal;
public:
CallBack( Obj* object, void (Obj::*func)(int) )
: CallBackBase()
{
m_object = object;
m_func = func;
nextCallBack = 0;
}
~CallBack() {;}
virtual void call( int val ) override
{ (m_object->*m_func)(val); }
private:
Obj* m_object;
void (Obj::*m_func)(uint8_t);
};
```
And this is our signal class:
We can add callbacks with the function connect() and remove callbacks with the function disconnect().
On emitValue() we call all the callbacks with an integer value as argument:
```c
class Signal
{
public:
Signal()
{
m_slot = 0;
}
~Signal() // Free resources created
{
CallBackBase* slot = m_slot;
while( slot ) // delete slots
{
CallBackBase* slotDel = slot;
slot = slot->nextCallBack;
delete slotDel;
} }
template <class Obj>
void connect( Obj* obj, void (Obj::*func)(int) )
{
CallBack<Obj>* slot = new CallBack<Obj>( obj, func );
slot->nextCallBack = m_slot;
m_slot = slot;
}
template <class Obj>
void disconnect( Obj* obj, void (Obj::*func)(int) )
{
CallBackBase* preSlot = 0;
CallBackBase* posSlot = m_slot;
while( posSlot )
{
CallBack<Obj>* cb = dynamic_cast<CallBack<Obj>*>(posSlot);
if( cb->m_object == obj && cb->m_func == func )
{
if( preSlot ) preSlot->nextCallBack = posSlot->nextCallBack;
else m_slot = posSlot->nextCallBack;
delete posSlot;
break;
}
preSlot = posSlot;
posSlot = posSlot->nextCallBack;
} }
void emitValue( int val ) // Calls all connected CallBacks
{
CallBackBase* slot = m_slot;
while( slot )
{
slot->call( val );
slot = slot->nextCallBack;
} }
private:
CallBackBase* m_slot;
};
```
To use it we create signals, connect callbacks and call emitValue() when needed.
```c
AnObjectClass* anObject = new AnObjectClass();
OtherObjectClass* otherObject = new OtherObjectClass();
ThirdObjectClass* thirdObject = new ThirdObjectClass();
OtherObjectClass* otherObject2 = new OtherObjectClass();
Signal on_write;
on_write.connect( anObject, &AnObjectClass::writeFunc );
on_write.connect( otherObject, &OtherObjectClass::otherFunc );
Signal on_read;
on_read.connect( thirdObject, &ThirdObjectClass::readFunc );
on_read.connect( otherObject2, &OtherObjectClass::someFunc );
void on_write_event( int value )
{
on_write.emitValue( value );
}
void on_read_event( int value )
{
on_read.emitValue( value );
}
```