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 ); } ```