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
43namespace Pt {
44
45class 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
188template <typename... As>
189class 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
219 {
220 this->disconnectSlots();
221 }
222
225 template <typename R>
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
282template <typename... As>
283class 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
331template <typename... As>
333{
334 return SignalSlot<As...>(signal);
335}
336
341template <typename R, typename... As>
343{
344 return signal.connect(slot);
345}
346
351template <typename R, typename... As>
353{
354 signal.disconnect(slot);
355}
356
357struct PT_API CompareEventTypeInfo
358{
359 bool operator()( const std::type_info* t1,
360 const std::type_info* t2 ) const;
361};
362
363template <>
364class 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
502template <typename R, class EventT>
504{
505 return signal.connect( slot );
506}
507
508template <typename R>
510{
511 return signal.connect( slot );
512}
513
514
515template <typename R, class EventT>
516void operator -=(Signal<const Pt::Event&>& signal, const BasicSlot<R, EventT>& slot)
517{
518 signal.disconnect( slot );
519}
520
521template <typename R>
522void 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
Base type for various "slot" types.
Definition Slot.h:92
Connection Management for Signal and Slot Objects.
Definition Connectable.h:50
Represents a connection between a Signal/Delegate and a slot.
Definition Connection.h:96
Connection()
Default Constructor.
Interface for invokable entities.
Definition Invokable.h:57
virtual void invoke(As... args) const =0
Invokes the invokable entity with the given arguments.
Adapter for class methods.
Definition Method.h:48
Wraps Signal objects so that they can act as Slots.
Definition Signal.h:284
SignalSlot(Signal< As... > &signal)
Constructs from signal.
Definition Signal.h:288
virtual const Callback * callable() const
Returns the callable converted to the type-erased Callback interface.
Definition Signal.h:299
virtual bool equals(const Slot &rhs) const
Returns true if two slots are equal in value.
Definition Signal.h:317
virtual void onConnect(const Connection &c)
Notifies of connects.
Definition Signal.h:305
virtual void onDisconnect(const Connection &c)
Notifies of disconnects.
Definition Signal.h:311
Slot * clone() const
Clone this object with new.
Definition Signal.h:293
Multicast Signal to call multiple slots.
Definition Signal.h:190
void disconnect(const BasicSlot< R, As... > &slot)
Disconnects from a slot.
Definition Signal.h:226
Signal()
Default constructor.
Definition Signal.h:196
void operator-=(Signal< As... > &signal, const BasicSlot< R, As... > &slot)
Disconnects a Signal fro a slot.
Definition Signal.h:352
void send(As... args)
Invlokes all slots.
Definition Signal.h:237
void disconnect()
Disconnects from current slots.
Definition Signal.h:218
Connection operator+=(Signal< As... > &signal, const BasicSlot< R, As... > &slot)
Connects a Signal to a slot.
Definition Signal.h:342
Connection connect(const BasicSlot< R, As... > &slot)
Connects to a slot.
Definition Signal.h:211
void operator()(As... args)
Invlokes all slots.
Definition Signal.h:268
Signal(const Signal &rhs)
Copy Constructor.
Definition Signal.h:200
Endpoint of a signal/slot connection.
Definition Slot.h:55
SignalSlot< As... > slot(Signal< As... > &signal)
Returns a slot object for the given signal.
Definition Signal.h:332
ConstMethodSlot< R, ClassT, As... > slot(ClassT &object, R(BaseT::*method)(As...) const)
Returns a slot object for the given object/member pair.
Definition ConstMethod.h:172
Core module.
Definition Allocator.h:33