ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/include/common/callback.h.in
Revision: 1.3
Committed: Tue Aug 28 17:12:24 2007 UTC (16 years, 9 months ago) by pippijn
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +1 -1 lines
State: FILE REMOVED
Log Message:
removed old files

File Contents

# Content
1 /*
2 * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
3 * Rights to this code are as documented in doc/pod/gplicense.pod.
4 *
5 * A C++ callback system inspired by Boost.Signals.
6 *
7 * $Id: callback.h.in,v 1.2 2007-07-25 01:05:17 pippijn Exp $
8 */
9
10 #ifndef CALLBACK_H
11 #define CALLBACK_H
12
13 #include <set>
14 #include <list>
15
16 namespace callback
17 {
18 class event_base;
19
20 class has_listeners
21 {
22 private:
23 typedef std::set <event_base *> sender_set;
24 typedef sender_set::const_iterator const_iterator;
25 typedef sender_set::iterator iterator;
26
27 sender_set m_senders;
28 sender_set &invokers ();
29
30 const sender_set &invokers () const;
31
32 public:
33 has_listeners ();
34 has_listeners (const has_listeners &rhs);
35
36 virtual ~has_listeners ();
37
38 has_listeners &operator = (const has_listeners &rhs);
39
40 void add_invoker (event_base *sender);
41 void remove_invoker (event_base *sender);
42
43 protected:
44 void copy_invokers (const has_listeners &rhs);
45 void disconnect_all ();
46 };
47
48 typedef has_listeners listening_base;
49
50
51 class event_base
52 {
53 public:
54 virtual ~event_base () { }
55 event_base () { }
56
57 inline bool detach (listening_base *plistener)
58 {
59 return this->listener_detach (plistener);
60 }
61
62 virtual bool listener_duplicate (const listening_base *poldlistener, listening_base *pnewlistener) = 0;
63
64 protected:
65 virtual bool listener_detach (listening_base *plistener) = 0;
66
67 template <typename list_T>
68 void free_connections (list_T &list)
69 {
70 typename list_T::const_iterator it;
71 typename list_T::const_iterator it_end = list.end ();
72
73 for (it = list.begin (); it != it_end; ++it)
74 {
75 (*it)->getdest ()->remove_invoker (this);
76 delete *it;
77 }
78
79 list.clear ();
80 }
81
82 template <typename list_T>
83 bool detach (listening_base *plistener, list_T &list)
84 {
85 typename list_T::iterator it;
86 typename list_T::iterator it_end = list.end ();
87
88 for (it = list.begin (); it != it_end; ++it)
89 {
90 if ((*it)->getdest () == plistener)
91 {
92 delete *it;
93 list.erase (it);
94 plistener->remove_invoker (this);
95
96 return true;
97 }
98 }
99
100 return false;
101 }
102
103 template <typename listeningT, typename SetT>
104 bool duplicate_connection (const listeningT *oldtarget, listeningT *newtarget, SetT &list)
105 {
106 typename SetT::iterator it = list.begin ();
107 typename SetT::iterator it_end = list.end ();
108
109 bool ret = false;
110 for (; it != it_end; ++it)
111 {
112 if ((*it)->getdest () == oldtarget)
113 {
114 list.push_back ((*it)->duplicate (newtarget));
115 ret = true;
116 }
117 }
118 return ret;
119 }
120
121 template <typename SetT>
122 void copy_connections (const SetT &src, SetT &tgt)
123 {
124 if (&src == &tgt)
125 return ;
126 typename SetT::const_iterator it = src.begin ();
127 typename SetT::const_iterator it_end = src.end ();
128 typedef typename SetT::value_type ConT;
129 ConT clone = 0;
130 for (; it != it_end; ++it)
131 {
132 clone = (*it)->clone ();
133 if (!clone)
134 continue;
135 clone->getdest ()->add_invoker (this);
136 tgt.push_back (clone);
137 }
138 }
139 };
140
141 class connection_base0
142 {
143 public:
144 virtual ~connection_base0 () { }
145 typedef connection_base0 this_type;
146 virtual listening_base *getdest () const = 0;
147 virtual void invoke () const = 0;
148
149 virtual this_type *clone () const = 0;
150 virtual this_type *duplicate (listening_base *pnewdest) const = 0;
151 };
152
153
154 template <class arg1_type>
155 class connection_base1
156 {
157 public:
158 virtual ~connection_base1 () { }
159 typedef connection_base1 <arg1_type> this_type;
160 virtual listening_base *getdest () const = 0;
161 virtual void invoke (arg1_type) const = 0;
162
163 virtual this_type *clone () const = 0;
164 virtual this_type *duplicate (listening_base *pnewdest) const = 0;
165 };
166
167
168 template <class dest_type>
169 class connection0 : public connection_base0
170 {
171 public:
172 typedef connection_base0 base_type;
173 typedef connection0<dest_type> this_type;
174
175 typedef void (dest_type::*listener_fun) ();
176 connection0 (): m_pobject (0), m_pmemfun (0){}
177
178 virtual ~connection0 () { }
179
180 connection0 (dest_type *pobject, listener_fun pmemfun): m_pobject (pobject), m_pmemfun (pmemfun){}
181
182 virtual base_type *clone () const
183 {
184 return new this_type (*this);
185 }
186
187 virtual base_type *duplicate (listening_base *pnewdest) const
188 {
189 return new this_type (dynamic_cast <dest_type *> (pnewdest), m_pmemfun);
190 }
191
192 virtual void invoke () const
193 {
194 (m_pobject->*m_pmemfun) ();
195 }
196
197 virtual listening_base *getdest () const
198 {
199 return m_pobject;
200 }
201
202 private:
203 dest_type *m_pobject;
204 listener_fun m_pmemfun;
205 };
206
207 template <class dest_type, class arg1_type>
208 class connection1 : public connection_base1<arg1_type>
209 {
210 public:
211 typedef connection_base1<arg1_type> base_type;
212 typedef connection1<dest_type, arg1_type> this_type;
213 typedef void (dest_type::*listener_fun) (arg1_type);
214 connection1 (): m_pobject (0), m_pmemfun (0){}
215
216 connection1 (dest_type *pobject, listener_fun pmemfun): m_pobject (pobject), m_pmemfun (pmemfun){}
217
218 virtual ~connection1 () { }
219
220 virtual base_type *clone () const
221 {
222 return new this_type (*this);
223 }
224
225 virtual base_type *duplicate (listening_base *pnewdest) const
226 {
227 return new this_type (dynamic_cast <dest_type *> (pnewdest), m_pmemfun);
228 }
229
230 virtual void invoke (arg1_type a1) const
231 {
232 (m_pobject->*m_pmemfun) (a1);
233 }
234
235 virtual listening_base *getdest () const
236 {
237 return m_pobject;
238 }
239
240 private:
241 dest_type *m_pobject;
242 listener_fun m_pmemfun;
243 };
244
245
246 class event0 : public event_base
247 {
248 public:
249 typedef std::list <connection_base0 *> connection_list;
250
251 event0 () { }
252
253 event0 (const event0 &s): event_base (s)
254 {
255 this->copy_connections (s.connections (), this->connections ());
256 }
257
258 event0 &operator = (const event0 &s)
259 {
260 this->copy_connections (s.connections (), this->connections ());
261 return *this;
262 }
263
264 virtual ~event0 ()
265 {
266 this->disconnect_all ();
267 }
268
269 void disconnect_all ()
270 {
271 this->free_connections (this->connections ());
272 }
273
274
275 template <class desttype>
276 void attach (desttype *pclass, void (desttype::*pmemfun) ())
277 {
278 connection_base0 *conn = new connection0<desttype> (pclass, pmemfun);
279 this->connections ().push_back (conn);
280 pclass->add_invoker (this);
281 }
282
283
284 bool listener_duplicate (const listening_base *oldtarget, listening_base *newtarget)
285 {
286 return this->duplicate_connection (oldtarget, newtarget, this->connections ());
287 }
288
289
290 void invoke () const
291 {
292 connection_list::const_iterator it;
293 connection_list::const_iterator end = this->connections ().end ();
294
295 for (it = this->connections ().begin (); it != end; ++it)
296 (*it)->invoke ();
297 }
298
299 void operator () () const
300 {
301 this->invoke ();
302 }
303
304 protected:
305 connection_list &connections ()
306 {
307 return this->m_connected_listeners;
308 }
309
310 const connection_list &connections () const
311 {
312 return this->m_connected_listeners;
313 }
314
315 bool listener_detach (listening_base *plistener)
316 {
317 return this->detach (plistener, this->connections ());
318 }
319
320 private:
321 connection_list m_connected_listeners;
322 };
323
324 template <class arg1_type>
325 class event1 : public event_base
326 {
327 public:
328 typedef std::list<connection_base1<arg1_type> *> connection_list;
329
330 event1 () { }
331
332 event1 (const event1 <arg1_type> &s): event_base (s) { }
333
334 template <class dest_type>
335 void attach (dest_type *pclass, void (dest_type::*pmemfun) (arg1_type))
336 {
337 connection_base1<arg1_type> *conn = new connection1<dest_type, arg1_type> (pclass, pmemfun);
338 this->connections ().push_back (conn);
339 pclass->add_invoker (this);
340 }
341
342 void invoke (arg1_type a1) const
343 {
344 typename connection_list::const_iterator it;
345 typename connection_list::const_iterator it_end = this->connections ().end ();
346
347 for (it = this->connections ().begin (); it != it_end; ++it)
348 {
349 (*it)->invoke (a1);
350 }
351 }
352
353 void operator () (arg1_type a1) const
354 {
355 this->invoke (a1);
356 }
357
358 event1 &operator = (const event1 &s)
359 {
360 this->copy_connections (s.connections (), this->connections ());
361 return *this;
362 }
363
364 bool listener_duplicate (const listening_base *oldtarget, listening_base *newtarget)
365 {
366 return this->duplicate_connection (oldtarget, newtarget, this->connections ());
367 }
368
369 ~event1 ()
370 {
371 this->disconnect_all ();
372 }
373
374 void disconnect_all ()
375 {
376 this->free_connections (connections ());
377 }
378
379 protected:
380 connection_list &connections ()
381 {
382 return this->m_connected_listeners;
383 }
384
385 const connection_list &connections () const
386 {
387 return this->m_connected_listeners;
388 }
389
390 bool listener_detach (listening_base *plistener)
391 {
392 return this->detach (plistener, this->connections ());
393 }
394
395 private:
396 connection_list m_connected_listeners;
397 };
398
399 @CALLBACKS@
400
401 } // namespace callback
402
403 class has_callbacks
404 {
405 protected:
406 struct callbacks
407 {
408 callback::event1 <has_callbacks *> created;
409 callback::event1 <has_callbacks *> destroyed;
410 };
411
412 static callbacks callback;
413
414 has_callbacks ();
415 ~has_callbacks ();
416 };
417
418 #endif // CALLBACK_H