Mercurial > ~dholland > hg > ag > index.cgi
comparison anagram/support/agsignal.h @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:13d2b8934445 |
---|---|
1 /* | |
2 * AnaGram, A System for Syntax Directed Programming | |
3 * Copyright 1993-2002 Parsifal Software. All Rights Reserved. | |
4 * See the file COPYING for license and usage terms. | |
5 * | |
6 * agsignal.h | |
7 */ | |
8 | |
9 #ifndef AGSIGNAL_H | |
10 #define AGSIGNAL_H | |
11 | |
12 #include "agstack.h" | |
13 #include "assert.h" | |
14 | |
15 /* | |
16 * The classes Broadcaster<Message> and Requester<Message> allow type-safe | |
17 * run-time binding to class methods where the name of the class containing | |
18 * the method being called is not known to the calling method. | |
19 * | |
20 * Any method m with the prototype | |
21 * void f(const Message &); | |
22 * belonging to an instance x of class X can by bound to a Broadcaster<Message> | |
23 * instance b in an instance y of a class Y by the following call: | |
24 * connect(&x, X::f, y.b); | |
25 * | |
26 * Any number of "listeners" may be attached to a given broadcaster. | |
27 * | |
28 * For each type of message that an object is to send, it must have a member | |
29 * object either of type Broadcaster<Message> or Requester<Message>, where | |
30 * Message is an arbitrary class. | |
31 * | |
32 * If an instance x of the class X has a member b of type Broadcaster<Message> | |
33 * a handler function h(const Message &) belonging to an instance, y, of an | |
34 * arbitrary class Y may be connected to the | |
35 * | |
36 * [...? the comment stopped here] | |
37 */ | |
38 | |
39 template <class Signal> | |
40 class Listener { | |
41 public: | |
42 Listener() {} | |
43 Listener(const Listener<Signal> &) {} | |
44 virtual ~Listener() {} | |
45 virtual void handle(const Signal &) { assert(0); } | |
46 virtual int operator == (const Listener<Signal> &p) const { | |
47 return p == *this; | |
48 } | |
49 virtual int operator < (const Listener<Signal> &) const { return 0; } | |
50 //virtual Listener<Signal> *copy() const { | |
51 // assert(0); | |
52 // return (Listener<Signal> *)this; | |
53 //} | |
54 virtual Listener<Signal> *copy() const { assert(0); return NULL; } | |
55 }; | |
56 | |
57 template <class Signal> | |
58 class Broadcaster { | |
59 private: | |
60 AgStack<Listener<Signal> *> listenerStack; | |
61 protected: | |
62 void broadcast(const Signal &) const; | |
63 public: | |
64 Broadcaster(int log = 3) : listenerStack(log) {} | |
65 void add(const Listener<Signal> &); | |
66 void remove(const Listener<Signal> &); | |
67 }; | |
68 | |
69 template <class Host, class Signal> | |
70 class ListenerFor : public Listener<Signal> { | |
71 private: | |
72 Host *host; | |
73 void (Host::*handler)(const Signal &); | |
74 public: | |
75 ListenerFor(Host *t, void (Host::*h)(const Signal &)) | |
76 : host(t), handler(h) {} | |
77 ListenerFor(const ListenerFor<Host, Signal> &x) | |
78 : host(x.host), handler(x.handler) {} | |
79 void handle(const Signal &s) { (host->*handler)(s); } | |
80 int operator == (const Listener<Signal> &r) const { | |
81 const ListenerFor<Host,Signal> &rf = (const ListenerFor<Host,Signal> &) r; | |
82 return (host == rf.host && handler == rf.handler); | |
83 } | |
84 int operator < (const Listener<Signal> &r) const { | |
85 const ListenerFor<Host,Signal> &rf = (const ListenerFor<Host,Signal> &) r; | |
86 return host == rf.host ? &handler < &rf.handler : host < rf.host; | |
87 } | |
88 ListenerFor<Host,Signal> *copy() const { | |
89 return new ListenerFor<Host,Signal>(host, handler); | |
90 } | |
91 }; | |
92 | |
93 template <class Signal> | |
94 void Broadcaster<Signal>::add(const Listener<Signal> &s) { | |
95 int n = listenerStack.size(); | |
96 int i; | |
97 for (i = 0; i < n; i++) { | |
98 if (s == *listenerStack[i]) { | |
99 return; | |
100 } | |
101 } | |
102 listenerStack.push(s.copy()); | |
103 } | |
104 | |
105 template <class Signal> | |
106 void Broadcaster<Signal>::remove(const Listener<Signal> &s) { | |
107 int n = listenerStack.size(); | |
108 int i; | |
109 for (i = 0; i < n; i++) { | |
110 if (s == *listenerStack[i]) { | |
111 break; | |
112 } | |
113 } | |
114 if (i == n) { | |
115 return; | |
116 } | |
117 delete listenerStack[i]; | |
118 while (++i < n) { | |
119 listenerStack[i-1] = listenerStack[i]; | |
120 } | |
121 listenerStack.pop(); | |
122 } | |
123 | |
124 template <class Signal> | |
125 void Broadcaster<Signal>::broadcast(const Signal &s) const { | |
126 int n = listenerStack.size(); | |
127 int i; | |
128 for (i = 0; i < n; i++) { | |
129 listenerStack[i]->handle(s); | |
130 } | |
131 } | |
132 | |
133 template <class Host, class Signal> | |
134 void connect(Host *host, void (Host::*handler)(const Signal &), | |
135 Broadcaster<Signal> &broadcaster) { | |
136 broadcaster.add(ListenerFor<Host,Signal>(host, handler)); | |
137 } | |
138 | |
139 template <class Host, class Signal> | |
140 void disconnect(Host *host, void (Host::*handler)(const Signal &), | |
141 Broadcaster<Signal> &broadcaster) { | |
142 broadcaster.remove(ListenerFor<Host,Signal>(host, handler)); | |
143 } | |
144 | |
145 template <class Signal> | |
146 class Responder { | |
147 public: | |
148 virtual void handle(Signal &) = 0; | |
149 virtual int operator == (const Responder<Signal> &p) const = 0; | |
150 virtual int operator == (const Responder<Signal> *p) const { | |
151 return *p == *this; | |
152 } | |
153 virtual Responder<Signal> *copy() const = 0; | |
154 }; | |
155 | |
156 template <class Signal> | |
157 class Requester { | |
158 private: | |
159 AgStack<Responder<Signal> *> responderStack; | |
160 int level; | |
161 | |
162 protected: | |
163 void request(Signal &); | |
164 | |
165 public: | |
166 Requester() : responderStack(3), level(0) {} | |
167 void add(const Responder<Signal> &r) { | |
168 responderStack.push(r.copy()); | |
169 level++; | |
170 } | |
171 void add(Responder<Signal> *r) { | |
172 responderStack.push(r); | |
173 level++; | |
174 } | |
175 void remove(const Responder<Signal> &); | |
176 Responder<Signal> *pop() { return responderStack.pop(); } | |
177 }; | |
178 | |
179 template <class Host, class Signal> | |
180 class ResponderFor : public Responder<Signal> { | |
181 private: | |
182 Host *host; | |
183 void (Host::*handler)(Signal &); | |
184 | |
185 public: | |
186 ResponderFor(Host *t, void (Host::*h)(Signal &)) : host(t), handler(h) {} | |
187 void handle(Signal &s) { (host->*handler)(s); } | |
188 int operator == (const Responder<Signal> &r) const { | |
189 const ResponderFor<Host,Signal> &rf = | |
190 (const ResponderFor<Host,Signal> &) r; | |
191 return (host == rf.host && handler == rf.handler); | |
192 } | |
193 Responder<Signal> *copy() const { | |
194 return new ResponderFor<Host,Signal>(host, handler); | |
195 } | |
196 }; | |
197 | |
198 template <class Signal> | |
199 void Requester<Signal>::remove(const Responder<Signal> &s) { | |
200 int n = responderStack.size(); | |
201 int i; | |
202 for (i = 0; i < n; i++) { | |
203 if (s == responderStack[i]) { | |
204 break; | |
205 } | |
206 } | |
207 if (i == n) { | |
208 return; | |
209 } | |
210 delete responderStack[i]; | |
211 if (level >= i) { | |
212 level--; | |
213 } | |
214 while (++i < n) { | |
215 responderStack[i-1] = responderStack[i]; | |
216 } | |
217 responderStack.pop(); | |
218 } | |
219 | |
220 template <class Signal> | |
221 void Requester<Signal>::request(Signal &s) { | |
222 assert(level > 0); | |
223 level--; | |
224 responderStack[level]->handle(s); | |
225 level++; | |
226 } | |
227 | |
228 template <class Host, class Signal> | |
229 void connect(Host *host, void (Host::*handler)(Signal &), | |
230 Requester<Signal> &requester) { | |
231 requester.add(ResponderFor<Host,Signal>(host, handler)); | |
232 } | |
233 | |
234 template <class Host, class Signal> | |
235 void disconnect(Host *host, void (Host::*handler)(Signal &), | |
236 Requester<Signal> &requester) { | |
237 requester.add(ResponderFor<Host,Signal>(host, handler)); | |
238 } | |
239 | |
240 template <class Signal> | |
241 void reroute(Requester<Signal> &from, Requester<Signal> &to) { | |
242 to.add(from.pop()); | |
243 } | |
244 | |
245 | |
246 #endif /* AGSIGNAL_H */ |