[C/C++] Mimicking Signal and Slot

“Signal and Slot” concept in QT is very impressive. So, I mimicked it. Here is my mimicked version sample.
(I know… This is humble… But, it has been useful for me..)

typedef struct {
  void*   obj;
  void*   func;
}___yZw_yzW_FiT___;
...
typedef void (*___yZw_yzW_FuncT1___) (void*, void*);
...
#define SLOT1_TYPE  ___yZw_yzW_FuncT1___
...
#define DEF_SLOT1(cLASS, sLOT, tYPE1) \
void  sLOT (tYPE1); \
static void ___##sLOT##_yZw_s___( void* ___yZw_t___,  \
                                  void* ___yZw_d1___) {\
  ASSERT( ___yZw_t___ && ___yZw_d1___ ); \
  tYPE1 a1;\
  memcpy(&a1, ___yZw_d1___, sizeof(tYPE1)); \
  ((cLASS*)___yZw_t___)->sLOT(a1); \
}
...
#define DEF_SIGNAL1(cLASS, sIGNAL, tYPE1) \
CArr<___yZw_yzW_FiT___>    ___yZw_##sIGNAL##_a___;\
void sIGNAL (tYPE1 ___yZw_a1) const { \
  for(int i=0; i<___yZw_##sIGNAL##_a___.Size(); i++) {\
    (*((___yZw_yzW_FuncT1___)(___yZw_##sIGNAL##_a___[i].func)))(___yZw_##sIGNAL##_a___[i].obj, \
                                                                (void*)&___yZw_a1 ); \
  }\
}
...
// argument [sIG_CLASS] is reserved for future use.
#define CONNECT(sIG_CLASS, sIG_OBJ, sIGNAL, sLOT_CLASS, sLOT_OBJ, sLOT) \
do{\
  int __yZw_i__; \
  for(__yZw_i__=0; __yZw_i__<(sIG_OBJ)->___yZw_##sIGNAL##_a___.Size(); __yZw_i__++){ \
    if( ((sIG_OBJ)->___yZw_##sIGNAL##_a___[__yZw_i__].obj == (void*)(sLOT_OBJ)) && \
      ((sIG_OBJ)->___yZw_##sIGNAL##_a___[__yZw_i__].func == (void*)&sLOT_CLASS::___##sLOT##_yZw_s___) ){ break; } \
  } \
\
  if(__yZw_i__ >= (sIG_OBJ)->___yZw_##sIGNAL##_a___.Size() ) \
  { /* Not in the list */ \
    ___yZw_yzW_FiT___   _info; \
    _info.obj = (void*)(sLOT_OBJ); \
    _info.func = (void*)(&sLOT_CLASS::___##sLOT##_yZw_s___); \
    ((sIG_OBJ)->___yZw_##sIGNAL##_a___).Append(_info); \
  } \
  else {;/* do nothing - duplicated slot is not allowed */ } \
}while(0);

// argument [sIG_CLASS] is reserved for future use.
#define DISCONNECT(sIG_CLASS, sIG_OBJ, sIGNAL, sLOT_CLASS, sLOT_OBJ, sLOT) \
do{ \
  int __yZw_i__; \
  for(__yZw_i__=0; __yZw_i__<(sIG_OBJ)->___yZw_##sIGNAL##_a___.Size(); __yZw_i__++){ \
    if( ((sIG_OBJ)->___yZw_##sIGNAL##_a___[__yZw_i__].obj == (sLOT_OBJ)) && \
      ((sIG_OBJ)->___yZw_##sIGNAL##_a___[__yZw_i__].func == &sLOT_CLASS::___##sLOT##_yZw_s___) ){ break; } \
  } \
  if( __yZw_i__<(sIG_OBJ)->___yZw_##sIGNAL##_a___.Size() ) { ((sIG_OBJ)->___yZw_##sIGNAL##_a___).Remove(__yZw_i__); } \
}while(0);
...

Here is example code to use this.

// Class definition
class CObj1
{
public:
  CObj1(void){
    _a = 0; _b = 0;
  }

  // virtual DEF_SLOT overriding.
  void  Name(char*);

  // DEF_SLOT functions.
  DEF_SLOT1(CObj1, Set_A,
            int);
  DEF_SLOT1(CObj1, Set_B,
            int);

  // DEF_SIGNAL functions.
  DEF_SIGNAL1(CObj1, Put_A,
              int);
  DEF_SIGNAL1(CObj1, Put_B,
              int);

private:
  int   _a;
  int   _b;
};
...

// Main code

int main() {
  CObj1 o1_1;
  CObj1 o1_2;

  o1_1.Set_A(1);
  o1_1.Set_B(2);

  CONNECT(CObj1, &o1_1, Put_A,    // Signal
          CObj1, &o1_2, Set_B );  // Slot
  CONNECT(CObj1, &o1_1, Put_A,    // Signal
          CObj1, &o1_2, Set_A);   // Slot
  ...
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s