signal.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2004-2006 by Dr. Marc Boris Duerner
3  * Copyright (C) 2005 Stephan Beal
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * As a special exception, you may use this file as part of a free
11  * software library without restriction. Specifically, if other files
12  * instantiate templates or use macros or inline functions from this
13  * file, or you compile this file and link it with other files to
14  * produce an executable, this file does not by itself cause the
15  * resulting executable to be covered by the GNU General Public
16  * License. This exception does not however invalidate any other
17  * reasons why the executable file might be covered by the GNU Library
18  * General Public License.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23  * Lesser General Public License for more details.
24  *
25  * You should have received a copy of the GNU Lesser General Public
26  * License along with this library; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28  */
29 
30 #ifndef cxxtools_Signal_h
31 #define cxxtools_Signal_h
32 
33 #include <cxxtools/void.h>
34 #include <cxxtools/event.h>
35 #include <cxxtools/function.h>
36 #include <cxxtools/method.h>
37 #include <cxxtools/constmethod.h>
38 #include <cxxtools/connectable.h>
39 #include <list>
40 #include <map>
41 
42 
43 namespace cxxtools {
44 
47  class SignalBase : public Connectable
48  {
49  public:
50  struct Sentry
51  {
52  Sentry(const SignalBase* signal);
53 
54  ~Sentry();
55 
56  void detach();
57 
58  bool operator!() const
59  { return _signal == 0; }
60 
62  };
63 
64  SignalBase();
65 
66  ~SignalBase();
67 
68  SignalBase& operator=(const SignalBase& other);
69 
70  virtual void onConnectionOpen(const Connection& c);
71 
72  virtual void onConnectionClose(const Connection& c);
73 
74  void disconnectSlot(const Slot& slot);
75 
76  private:
77  mutable Sentry* _sentry;
78  mutable bool _sending;
79  mutable bool _dirty;
80  };
81 
82 
83 #include <cxxtools/signal.tpp>
84 
86 {
87  bool operator()( const std::type_info* t1,
88  const std::type_info* t2 ) const;
89 };
90 
91 template <>
92 class Signal<const cxxtools::Event&> : public Connectable
93 {
94  struct Sentry
95  {
96  Sentry(const Signal* signal);
97 
98  ~Sentry();
99 
100  void detach();
101 
102  bool operator!() const
103  { return _signal == 0; }
104 
105  const Signal* _signal;
106  };
107 
108  class IEventRoute
109  {
110  public:
111  IEventRoute(Connection& target)
112  : _target(target)
113  { }
114 
115  virtual ~IEventRoute() {}
116 
117  virtual void route(const cxxtools::Event& ev)
118  {
119  typedef Invokable<const cxxtools::Event&> InvokableT;
120  const InvokableT* invokable = static_cast<const InvokableT*>( _target.slot().callable() );
121  invokable->invoke(ev);
122  }
123 
125  { return _target; }
126 
127  bool valid() const
128  { return _target.valid(); }
129 
130  private:
131  Connection _target;
132  };
133 
134  template <typename EventT>
135  class EventRoute : public IEventRoute
136  {
137  public:
138  EventRoute(Connection& target)
139  : IEventRoute(target)
140  { }
141 
142  virtual void route(const cxxtools::Event& ev)
143  {
144  typedef Invokable<const cxxtools::Event&> InvokableT;
145  const InvokableT* invokable = static_cast<const InvokableT*>( connection().slot().callable() );
146 
147  const EventT& event = static_cast<const EventT&>(ev);
148  invokable->invoke(event);
149  }
150  };
151 
152  typedef std::multimap< const std::type_info*,
153  IEventRoute*,
154  CompareEventTypeInfo > RouteMap;
155 
156  // make non copyable
157 #if __cplusplus >= 201103L
158  Signal(const Signal&) = delete;
159  Signal& operator=(const Signal&) = delete;
160 #else
161  Signal(const Signal&) { }
162  Signal& operator=(const Signal&) { return *this; }
163 #endif
164 
165  public:
166  Signal();
167 
168  ~Signal();
169 
170  void send(const cxxtools::Event& ev) const;
171 
172  template <typename R>
173  Connection connect(const BasicSlot<R, const cxxtools::Event&>& slot)
174  {
175  Connection conn( *this, slot.clone() );
176  this->addRoute( 0, new IEventRoute(conn) );
177  return conn;
178  }
179 
180  template <typename R>
181  void disconnect(const BasicSlot<R, const cxxtools::Event&>& slot)
182  {
183  this->removeRoute(slot);
184  }
185 
186  template <typename EventT>
187  void subscribe( const BasicSlot<void, const EventT&>& slot )
188  {
189  Connection conn( *this, slot.clone() );
190  const std::type_info& ti = typeid(EventT);
191  this->addRoute( &ti, new EventRoute<EventT>(conn) );
192  }
193 
194  template <typename EventT>
195  void unsubscribe( const BasicSlot<void, const EventT&>& slot )
196  {
197  const std::type_info& ti = typeid(EventT);
198  this->removeRoute(&ti, slot);
199  }
200 
201  virtual void onConnectionOpen(const Connection& c);
202 
203  virtual void onConnectionClose(const Connection& c);
204 
205  protected:
206  void addRoute(const std::type_info* ti, IEventRoute* route);
207 
208  void removeRoute(const Slot& slot);
209 
210  void removeRoute(const std::type_info* ti, const Slot& slot);
211 
212  private:
213  mutable RouteMap _routes;
214  mutable Sentry* _sentry;
215  mutable bool _sending;
216  mutable bool _dirty;
217 };
218 
219 template <typename R>
221 {
222  return signal.connect( slot(func) );
223 }
224 
225 template <typename R, class BaseT, class ClassT>
227  BaseT& object, R(ClassT::*memFunc)(const cxxtools::Event&) )
228 {
229  return signal.connect( slot(object, memFunc) );
230 }
231 
232 template <typename R, class BaseT, class ClassT>
233 Connection connect( Signal<const cxxtools::Event&>& signal,
234  BaseT& object, R(ClassT::*memFunc)(const cxxtools::Event&) const )
235 {
236  return signal.connect( slot(object, memFunc) );
237 }
238 
240 {
241  return sender.connect( slot(receiver) );
242 }
243 
244 template <typename R>
246 {
247  signal.disconnect( slot(func) );
248 }
249 
250 template <typename R, class BaseT, class ClassT>
252  BaseT& object, R(ClassT::*memFunc)(const cxxtools::Event&) )
253 {
254  signal.disconnect( slot(object, memFunc) );
255 }
256 
257 template <typename R, class BaseT, class ClassT>
258 void disconnect( Signal<const cxxtools::Event&>& signal,
259  BaseT& object, R(ClassT::*memFunc)(const cxxtools::Event&) const )
260 {
261  signal.disconnect( slot(object, memFunc) );
262 }
263 
265 {
266  sender.disconnect( slot(receiver) );
267 }
268 
269 } // !namespace cxxtools
270 
271 #endif