ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/include/common/callback.h.in
Revision: 1.2
Committed: Wed Jul 25 01:05:17 2007 UTC (19 years, 2 months ago) by pippijn
Branch: MAIN
Changes since 1.1: +6 -1 lines
Log Message:
- moved to GPL
- added license information to files

File Contents

# User Rev Content
1 pippijn 1.1 /*
2 pippijn 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: account.h,v 1.2 2007-07-21 01:29:07 pippijn Exp $
8 pippijn 1.1 */
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