IT++ Logo
signals_slots.h
Go to the documentation of this file.
1 
29 #ifndef SIGNAL_SLOT_H
30 #define SIGNAL_SLOT_H
31 
32 #include <itpp/itexports.h>
33 
34 #if (defined(_MSC_VER) && defined(ITPP_SHARED_LIB) && !(defined(itpp_EXPORTS) || defined(itpp_debug_EXPORTS)))
35 
36 #ifndef ITPP_PROTOCOL_EXCLUDED
37 #define ITPP_PROTOCOL_EXCLUDED
38 #pragma message( "PROTOCOL definitions are not available for MSVC shared builds" )
39 #endif
40 
41 #else
42 
43 #include <itpp/protocol/events.h>
44 #include <list>
45 #include <iostream>
46 
47 
48 namespace itpp
49 {
50 
52 
53 
54 class Base_Signal;
55 template<class DataType> class Signal;
56 template<class DataType> class Base_Slot;
57 template<class ObjectType, class DataType> class Slot;
58 
59 
123 template<class DataType>
124 class Signal
125 {
126 public:
127  friend class Base_Slot<DataType>;
128 
130  Signal(const std::string signal_name = "Unamed Signal", const bool single_shot = false, const bool enable_debug = false);
131 
132  // Signal(const std::string signal_name = "Unamed Signal", const bool single_shot = false, const bool enable_debug = true);
133 
135  ~Signal();
136 
138  void connect(Base_Slot<DataType>* slot);
139 
141  void disconnect(Base_Slot<DataType>* slot = NULL);
142 
143  // Base_Event* arm(const Ttype delta_time, DataType signal); // Signal will trigger in 'delta_time' time units carrying data signal.
144 
145 
147  Base_Event* operator()(DataType signal, const Ttype delta_time = 0);
148 
150  void cancel();
151 
153  void set_name(const std::string &signal_name);
154 
156  void set_debug(const bool enable_debug = true);
157 
159  void trigger(DataType u);
160 
161 protected:
163  typedef typename std::list<Base_Slot<DataType>*, std::allocator< Base_Slot<DataType>* > >::iterator Base_Slot_Iterator;
165  void _disconnect(Base_Slot<DataType>* slot);
167  std::list<Base_Slot<DataType>*, std::allocator<Base_Slot<DataType>* > > connected_slots;
169  std::string name;
170 
171 private:
172  bool armed;
173  bool debug;
174  bool single;
176 };
177 
178 
183 template<class DataType>
185 {
186 public:
187  friend class Signal<DataType>;
188 
190  Base_Slot(const std::string slot_name = "Unamed Base_Slot");
191 
193  virtual ~Base_Slot();
194 
196  void set_name(const std::string &slot_name);
197 
199  virtual void operator()(DataType signal) = 0;
200 
201 protected:
202  // virtual void exec(DataType signal) = 0;
204  typedef typename std::list<Signal<DataType>*, std::allocator< Signal<DataType>* > >::iterator Signal_Iterator;
206  std::string name;
208  void _connect(Signal<DataType>* signal);
210  void _disconnect(Signal<DataType>* signal);
212  std::list<Signal<DataType>*, std::allocator<Signal<DataType>* > > connected_signals;
213 };
214 
219 template<class ObjectType, class DataType>
220 class Slot : public Base_Slot<DataType>
221 {
222 public:
224  Slot(const std::string _name = "Unamed Slot");
225 
227  void forward(ObjectType *object_pointer, void(ObjectType::*object_function_pointer)(DataType u));
228 
230  ~Slot();
231 
233  void operator()(DataType u);
234 
235  //void exec(DataType signal);
236 
237 private:
238  ObjectType *po;
239  void(ObjectType::*pm)(DataType signal);
240 };
241 
242 
246 template<class ObjectType, class DataType>
247 class ATimer
248 {
249 public:
251  ATimer(const std::string Name = "Unamed ATimer") {
252  time_out_signal = new Signal<DataType>(Name, true);
253  time_out_slot = new Slot<ObjectType, DataType>(Name);
254  time_out_signal->connect(time_out_slot);
255  set_name(Name);
256  }
257 
259  void forward(ObjectType *po, void(ObjectType::*pm)(DataType u)) { time_out_slot->forward(po, pm); }
260 
262  void set(DataType u, const Ttype delta_t) {
263  time_out_signal->operator()(u, delta_t);
264  }
265 
267  void cancel() { time_out_signal->cancel(); }
268 
270  void set_name(const std::string Name) {
271  name = Name;
272  time_out_signal->set_name(name);
273  time_out_slot->set_name(name);
274  }
275 
276 protected:
278  std::string name;
279 
280 private:
281  Signal<DataType> *time_out_signal;
282  Slot<ObjectType, DataType> *time_out_slot;
283 };
284 
285 
286 
295 template <class THandler>
296 class TTimer
297 {
298 public:
300  TTimer(THandler & handler, void (THandler::*handlerFunction)(Ttype time)) :
301  signal("timer_signal", true) {
302  fPending = false;
303  fExpirationTime = 0;
304 
305  registered_handler = &handler;
306  registered_handler_function = handlerFunction;
307 
309  slot.set_name("timer_slot");
310  signal.set_debug(false);
311  signal.connect(&slot);
312  }
313 
315  virtual ~TTimer() {
316  if (fPending)
317  signal.cancel();
318  }
319 
321  void Set(Ttype time, bool relative = true) {
322  if (fPending)
323  signal.cancel();
324 
325  fPending = true;
326  double current_time = Event_Queue::now();
327  double delta_time;
328  if (relative) {
329  fExpirationTime = current_time + time;
330  delta_time = time;
331  }
332  else {
333  fExpirationTime = time;
334  delta_time = time - current_time;
335  }
336  signal(fExpirationTime, delta_time);
337  }
338 
340  void Reset() {
341  if (fPending) {
342  signal.cancel();
343  fPending = false; // TODO: Added this myself. Didn't work otherwise.
344  }
345  }
346 
349  it_assert(fPending, "TTimer<>::ExpirationTime: timer not set");
350  return fExpirationTime;
351  }
352 
354  bool IsPending() const { return fPending; }
355 
356 protected:
358  virtual void HandleProcessEvent(Ttype currentTime) {
359  fPending = false;
360  (*registered_handler.*registered_handler_function)(currentTime);
361  }
362 
364  virtual void HandleCancelEvent(Ttype) {
365  if (fPending)
366  signal.cancel();
367 
368  fPending = false;
369  }
370 
372  bool fPending;
375 
376 private:
377  THandler *registered_handler;
378  void(THandler::*registered_handler_function)(Ttype expiry_time);
379 
380  Signal<double> signal; // Used internally
381  Slot<TTimer, double> slot; // Used internally
382 };
383 
384 
385 
386 
387 
388 
389 // -----------------------------------------------------------------------------------------------
390 
391 template<class DataType>
392 Signal<DataType>::Signal(const std::string signal_name, const bool single_shot, const bool enable_debug)
393 {
394  armed = false;
395  e = NULL;
396  single = single_shot;
397  set_name(signal_name);
398  set_debug(enable_debug);
399 }
400 
401 template<class DataType>
403 {
405  begin = connected_slots.begin(),
406  end = connected_slots.end(),
407  i;
408 
409  for (i = begin; i != end; i++)
410  (*i)->_disconnect(this);
411 
412  connected_slots.clear();
413 
414  if (e != NULL) // Cancel a possibly pending event since we are about to die!
415  e->cancel();
416 }
417 
418 template<class DataType>
419 void Signal<DataType>::set_name(const std::string &signal_name)
420 {
421  name = signal_name;
422 }
423 
424 template<class DataType>
425 void Signal<DataType>::set_debug(const bool enable_debug)
426 {
427  debug = enable_debug;
428 }
429 
430 template<class DataType>
432 {
434  begin = connected_slots.begin(),
435  end = connected_slots.end(),
436  i;
437 
438  bool is_already_connected = false;
439 
440  for (i = begin; i != end; i++)
441  if ((*i) == slot)
442  is_already_connected = true;
443 
444  if (!is_already_connected) { // Multiple connections is meaningless.
445  connected_slots.push_back(slot);
446  slot->_connect(this); // Needed if a connected slot is deleted during run time.
447  }
448  else {
449  std::cout << "Signal '" << name << "' and Slot '" << slot->name << "' are already connected. Multiple connections have no effect!" << std::endl;
450  }
451 }
452 
453 template<class DataType>
455 {
457  begin = connected_slots.begin(),
458  end = connected_slots.end(),
459  i;
460 
461  for (i = begin; i != end; i++)
462  if ((*i) == slot) {
463  (*i)->_disconnect(this);
464  connected_slots.erase(i);
465  break;
466  }
467 }
468 
469 template<class DataType>
470 Base_Event* Signal<DataType>::operator()(DataType signal, const Ttype delta_time)
471 {
472  // Signal will trigger in 'delta_time' time units.
473  if (single) { // We are operating in single-shot mode.
474  if (armed) { // Cancel and schedule again with the new 'delta_time'.
475  if (debug)
476  std::cout << "Warning: Changing time for Signal '" << name << "'." << std::endl;
477  cancel();
478  operator()(signal, delta_time);
479  }
480  else {
481  e = new Data_Event<Signal, DataType>(this, &Signal<DataType>::trigger, signal, delta_time);
482  armed = true;
483  Event_Queue::add(e);
484  }
485  }
486  else { // Continious mode (cancel() has no effect).
487  e = new Data_Event<Signal, DataType>(this, &Signal<DataType>::trigger, signal, delta_time);
488  armed = true;
489  Event_Queue::add(e);
490  }
491  return e;
492 }
493 
494 template<class DataType>
496 {
497  if (armed && single) {
498  e->cancel();
499  e = NULL;
500  armed = false;
501  }
502 }
503 
504 
505 template<class DataType>
507 {
508  armed = false;
509  e = NULL;
511  begin = connected_slots.begin(),
512  end = connected_slots.end(),
513  i;
514 
515  for (i = begin; i != end; i++) { // Execute all the functions of the connected slots.
516  if (debug)
517  std::cout << "Time = " << Event_Queue::now() << ". Signal '" << name << "' was sent to Slot '" << (*i)->name << "'." << std::endl;
518  (*i)->operator()(u);
519  }
520 }
521 
522 template<class DataType>
524 {
526  begin = connected_slots.begin(),
527  end = connected_slots.end(),
528  i;
529 
530  for (i = begin; i != end; i++)
531  if ((*i) == slot) {
532  connected_slots.erase(i);
533  break;
534  }
535 }
536 
537 
538 template<class DataType>
539 Base_Slot<DataType>::Base_Slot(const std::string slot_name)
540 {
541  set_name(slot_name);
542 }
543 
544 template<class DataType>
545 void Base_Slot<DataType>::set_name(const std::string &slot_name)
546 {
547  name = slot_name;
548 }
549 
550 template<class DataType>
552 { // Notify all signals connect that we are being deleted ...
553 
555  begin = connected_signals.begin(),
556  end = connected_signals.end(),
557  i;
558 
559  for (i = begin; i != end; i++)
560  (*i)->_disconnect(this);
561 
562  connected_signals.clear();
563 }
564 
565 template<class DataType>
567 { // A signal is being connected to us.
568  connected_signals.push_back(signal);
569 }
570 
571 template<class DataType>
573 { // A signal is being disconnected from us.
574 
576  begin = connected_signals.begin(),
577  end = connected_signals.end(),
578  i;
579 
580  for (i = begin; i != end; i++)
581  if ((*i) == signal) {
582  connected_signals.erase(i);
583  break;
584  }
585 }
586 
587 template<class ObjectType, class DataType>
588 Slot<ObjectType, DataType>::Slot(const std::string slot_name) : Base_Slot<DataType>(slot_name)
589 {
590  pm = NULL;
591  po = NULL;
592 }
593 
594 template<class ObjectType, class DataType>
596 
597 template<class ObjectType, class DataType>
598 void Slot<ObjectType, DataType>::forward(ObjectType *object_pointer, void(ObjectType::*object_function_pointer)(DataType u))
599 {
600  pm = object_function_pointer;
601  po = object_pointer;
602 }
603 
604 // template<class ObjectType, class DataType>
605 // void Slot<ObjectType, DataType>::exec(DataType signal){
606 // if(pm&&po)
607 // (*po.*pm)(signal);
608 // }
609 
610 template<class ObjectType, class DataType>
612 {
613  if (pm&&po)
614  (*po.*pm)(signal);
615 }
616 
618 
619 } // namespace itpp
620 
621 #endif
622 
623 #endif // #ifndef SIGNAL_SLOT_H
624 
SourceForge Logo

Generated on Sat May 25 2013 16:32:23 for IT++ by Doxygen 1.8.2