Signal.h
1 /*
2  Copyright (C) 2005-2013 by Dr. Marc Boris Duerner
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8 
9  As a special exception, you may use this file as part of a free
10  software library without restriction. Specifically, if other files
11  instantiate templates or use macros or inline functions from this
12  file, or you compile this file and link it with other files to
13  produce an executable, this file does not by itself cause the
14  resulting executable to be covered by the GNU General Public
15  License. This exception does not however invalidate any other
16  reasons why the executable file might be covered by the GNU Library
17  General Public License.
18 
19  This library is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  Lesser General Public License for more details.
23 
24  You should have received a copy of the GNU Lesser General Public
25  License along with this library; if not, write to the:
26  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27  Boston, MA 02110-1301 USA
28 */
29 
30 #ifndef Pt_Signal_h
31 #define Pt_Signal_h
32 
33 #include <Pt/Api.h>
34 #include <Pt/Void.h>
35 #include <Pt/Event.h>
36 #include <Pt/Slot.h>
37 #include <Pt/Function.h>
38 #include <Pt/Method.h>
39 #include <Pt/ConstMethod.h>
40 #include <Pt/Connectable.h>
41 #include <map>
42 
43 namespace Pt {
44 
45 class PT_API SignalBase : public Connectable
46 {
47  public:
48  struct PT_API Sentry
49  {
50  Sentry(SignalBase* signal);
51 
52  ~Sentry();
53 
54  void detachAll();
55 
56  void detach();
57 
58  bool operator!() const
59  { return _signal == 0; }
60 
61  SignalBase* _signal;
62  Sentry* _next;
63  };
64 
65  SignalBase();
66 
67  ~SignalBase();
68 
69  SignalBase& operator=(const SignalBase& other);
70 
71  virtual void onConnectionOpen(const Connection& c);
72 
73  virtual void onConnectionClose(const Connection& c);
74 
75  protected:
76  void disconnectSlots();
77 
78  void disconnectSlot(const Slot&);
79 
80  private:
81  Sentry* _sentry;
82  bool _sending;
83  bool _dirty;
84 };
85 
188 template <typename... As>
189 class Signal : public SignalBase
190 {
191  public:
192  typedef Invokable<As...> InvokableT;
193 
194  public:
197  { }
198 
200  Signal(const Signal& rhs)
201  {
202  SignalBase::operator=(rhs);
203  }
204 
210  template <typename R>
212  {
213  return Connection(*this, slot.clone());
214  }
215 
218  void disconnect()
219  {
220  this->disconnectSlots();
221  }
222 
225  template <typename R>
226  void disconnect(const BasicSlot<R, As...>& slot)
227  {
228  this->disconnectSlot(slot);
229  }
230 
237  void send(As... args)
238  {
239  if( Connectable::connections().empty() )
240  return;
241 
242  SignalBase::Sentry sentry(this);
243 
244  std::list<Connection>::const_iterator it = Connectable::connections().begin();
245  std::list<Connection>::const_iterator last = --Connectable::connections().end();
246  while(true)
247  {
248  if( it->isValid() && it->sender() == this )
249  {
250  const InvokableT* invokable =
251  static_cast<const InvokableT*>( it->callable() );
252  invokable->invoke(args...);
253  }
254 
255  if( ! sentry )
256  return;
257 
258  if(it == last)
259  break;
260 
261  ++it;
262  }
263  }
264 
268  void operator()(As... args)
269  {
270  this->send(args...);
271  }
272 };
273 
282 template <typename... As>
283 class SignalSlot : public BasicSlot<void, As...>
284 {
285  public:
288  explicit SignalSlot(Signal<As...>& signal)
289  : _method( signal, &Signal<As...>::send )
290  {}
291 
292  // inherit doc
293  Slot* clone() const
294  {
295  return new SignalSlot(*this);
296  }
297 
298  // inherit doc
299  virtual const Callback* callable() const
300  {
301  return &_method;
302  }
303 
304  // inherit doc
305  virtual void onConnect(const Connection& c)
306  {
307  _method.object().onConnectionOpen(c);
308  }
309 
310  // inherit doc
311  virtual void onDisconnect(const Connection& c)
312  {
313  _method.object().onConnectionClose(c);
314  }
315 
316  // inherit doc
317  virtual bool equals(const Slot& rhs) const
318  {
319  const SignalSlot* ss = dynamic_cast<const SignalSlot*>(&rhs);
320  return ss ? (_method == ss->_method) : false;
321  }
322 
323  private:
324  Method<void, Signal<As...> , As...> _method;
325 };
326 
331 template <typename... As>
333 {
334  return SignalSlot<As...>(signal);
335 }
336 
341 template <typename R, typename... As>
343 {
344  return signal.connect(slot);
345 }
346 
351 template <typename R, typename... As>
352 void operator-=(Signal<As...>& signal, const BasicSlot<R, As...>& slot)
353 {
354  signal.disconnect(slot);
355 }
356 
357 struct PT_API CompareEventTypeInfo
358 {
359  bool operator()( const std::type_info* t1,
360  const std::type_info* t2 ) const;
361 };
362 
363 template <>
364 class PT_API Signal<const Pt::Event&> : public Connectable
365  , protected NonCopyable
366 {
367  struct PT_API Sentry
368  {
369  Sentry(Signal* signal);
370 
371  ~Sentry();
372 
373  void detach();
374 
375  void detachAll();
376 
377  bool operator!() const
378  { return _signal == 0; }
379 
380  Signal* _signal;
381  Sentry* _next;
382  };
383 
384  class IEventRoute
385  {
386  public:
387  IEventRoute(Connection& target)
388  : _target(target)
389  { }
390 
391  virtual ~IEventRoute() {}
392 
393  virtual void route(const Pt::Event& ev)
394  {
395  typedef Invokable<const Pt::Event&> InvokableT;
396  const InvokableT* invokable = static_cast<const InvokableT*>( _target.callable() );
397  invokable->invoke(ev);
398  }
399 
400  Connection& connection()
401  { return _target; }
402 
403  bool isValid() const
404  { return _target.isValid(); }
405 
406  private:
407  Connection _target;
408  };
409 
410  template <typename EventT>
411  class EventRoute : public IEventRoute
412  {
413  public:
414  EventRoute(Connection& target)
415  : IEventRoute(target)
416  { }
417 
418  virtual void route(const Pt::Event& ev)
419  {
420  typedef Invokable<const Pt::Event&> InvokableT;
421  const InvokableT* invokable = static_cast<const InvokableT*>( connection().callable() );
422 
423  const EventT& event = static_cast<const EventT&>(ev);
424  invokable->invoke(event);
425  }
426  };
427 
428  typedef std::multimap< const std::type_info*,
429  IEventRoute*,
430  CompareEventTypeInfo > RouteMap;
431 
432  public:
433  Signal();
434 
435  ~Signal();
436 
437  void send(const Pt::Event& ev);
438 
439  template <typename EventT>
440  Connection connect( const BasicSlot<void, const EventT&>& slot )
441  {
442  Connection conn( *this, slot.clone() );
443  EventT* selectAddRouteOverload = 0;
444  this->addRoute(conn, selectAddRouteOverload);
445  return conn;
446  }
447 
448  void disconnect();
449 
450  template <typename R, typename EventT>
451  void disconnect(const BasicSlot<R, const EventT&>& slot)
452  {
453  this->removeRoute(slot);
454  }
455 
456  virtual void onConnectionOpen(const Connection& c);
457 
458  virtual void onConnectionClose(const Connection& c);
459 
460  protected:
461  void addRoute(Connection& conn, const Pt::Event*)
462  {
463  this->addRoute( 0, new IEventRoute(conn) );
464  }
465 
466  template <typename EventT>
467  void addRoute(Connection& conn, const EventT*)
468  {
469  const std::type_info& ti = typeid(EventT);
470  this->addRoute( &ti, new EventRoute<EventT>(conn) );
471  }
472 
473  void addRoute(const std::type_info* ti, IEventRoute* route);
474 
475  void removeRoute(const Slot& slot);
476 
477  // TODO: Pt 2.0 (better performance)
478 
479  //template <typename R>
480  //void removeRoute(const BasicSlot<R, const Event&>& slot)
481  //{
482  // this->removeRoute(0, slot);
483  //}
484 
485  //template <typename R, typename EventT>
486  //void removeRoute(const BasicSlot<R, const EventT&>& slot)
487  //{
488  // const std::type_info& ti = typeid(EventT);
489  // this->removeRoute(&ti, slot);
490  //}
491 
492  void removeRoute(const std::type_info* ti, const Slot& slot);
493 
494  private:
495  RouteMap _routes;
496  Sentry* _sentry;
497  bool _sending;
498  bool _dirty;
499 };
500 
501 
502 template <typename R, class EventT>
503 Connection operator +=(Signal<const Pt::Event&>& signal, const BasicSlot<R, EventT>& slot)
504 {
505  return signal.connect( slot );
506 }
507 
508 template <typename R>
509 Connection operator +=(Signal<const Pt::Event&>& signal, const BasicSlot<R, const Pt::Event&>& slot)
510 {
511  return signal.connect( slot );
512 }
513 
514 
515 template <typename R, class EventT>
516 void operator -=(Signal<const Pt::Event&>& signal, const BasicSlot<R, EventT>& slot)
517 {
518  signal.disconnect( slot );
519 }
520 
521 template <typename R>
522 void operator -=(Signal<const Pt::Event&>& signal, const BasicSlot<R, const Pt::Event&>& slot)
523 {
524  signal.disconnect( slot );
525 }
526 
527 } // namespace Pt
528 
529 #endif
Core module.
Definition: Allocator.h:33
Slot * clone() const
Clone this object with new.
Definition: Signal.h:293
Adapter for class methods.
Definition: Method.h:48
Base class for all event types.
Definition: Event.h:50
virtual void onConnect(const Connection &c)
Notifies of connects.
Definition: Signal.h:305
Interface for invokable entities.
Definition: Invokable.h:57
void disconnect(const BasicSlot< R, As... > &slot)
Disconnects from a slot.
Definition: Signal.h:226
Multicast Signal to call multiple slots.
Definition: Signal.h:190
void disconnect()
Disconnects from current slots.
Definition: Signal.h:218
virtual Slot * clone() const =0
Clone this object with new.
virtual void invoke(As... args) const =0
Invokes the invokable entity with the given arguments.
Signal()
Default constructor.
Definition: Signal.h:196
Wraps Signal objects so that they can act as Slots.
Definition: Signal.h:284
virtual const Callback * callable() const
Returns the callable converted to the type-erased Callback interface.
Definition: Signal.h:299
void send(As... args)
Invlokes all slots.
Definition: Signal.h:237
Connection operator+=(Signal< As... > &signal, const BasicSlot< R, As... > &slot)
Connects a Signal to a slot.
Definition: Signal.h:342
SignalSlot< As... > slot(Signal< As... > &signal)
Returns a slot object for the given signal.
Definition: Signal.h:332
void operator()(As... args)
Invlokes all slots.
Definition: Signal.h:268
Endpoint of a signal/slot connection.
Definition: Slot.h:55
virtual bool equals(const Slot &rhs) const
Returns true if two slots are equal in value.
Definition: Signal.h:317
Signal(const Signal &rhs)
Copy Constructor.
Definition: Signal.h:200
Connection connect(const BasicSlot< R, As... > &slot)
Connects to a slot.
Definition: Signal.h:211
void operator-=(Signal< As... > &signal, const BasicSlot< R, As... > &slot)
Disconnects a Signal fro a slot.
Definition: Signal.h:352
Represents a connection between a Signal/Delegate and a slot.
Definition: Connection.h:96
virtual void onDisconnect(const Connection &c)
Notifies of disconnects.
Definition: Signal.h:311
SignalSlot(Signal< As... > &signal)
Constructs from signal.
Definition: Signal.h:288