Mercurial > ~dholland > hg > ag > index.cgi
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/anagram/support/agsignal.h Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,246 @@ +/* + * AnaGram, A System for Syntax Directed Programming + * Copyright 1993-2002 Parsifal Software. All Rights Reserved. + * See the file COPYING for license and usage terms. + * + * agsignal.h + */ + +#ifndef AGSIGNAL_H +#define AGSIGNAL_H + +#include "agstack.h" +#include "assert.h" + +/* + * The classes Broadcaster<Message> and Requester<Message> allow type-safe + * run-time binding to class methods where the name of the class containing + * the method being called is not known to the calling method. + * + * Any method m with the prototype + * void f(const Message &); + * belonging to an instance x of class X can by bound to a Broadcaster<Message> + * instance b in an instance y of a class Y by the following call: + * connect(&x, X::f, y.b); + * + * Any number of "listeners" may be attached to a given broadcaster. + * + * For each type of message that an object is to send, it must have a member + * object either of type Broadcaster<Message> or Requester<Message>, where + * Message is an arbitrary class. + * + * If an instance x of the class X has a member b of type Broadcaster<Message> + * a handler function h(const Message &) belonging to an instance, y, of an + * arbitrary class Y may be connected to the + * + * [...? the comment stopped here] + */ + +template <class Signal> +class Listener { +public: + Listener() {} + Listener(const Listener<Signal> &) {} + virtual ~Listener() {} + virtual void handle(const Signal &) { assert(0); } + virtual int operator == (const Listener<Signal> &p) const { + return p == *this; + } + virtual int operator < (const Listener<Signal> &) const { return 0; } + //virtual Listener<Signal> *copy() const { + // assert(0); + // return (Listener<Signal> *)this; + //} + virtual Listener<Signal> *copy() const { assert(0); return NULL; } +}; + +template <class Signal> +class Broadcaster { +private: + AgStack<Listener<Signal> *> listenerStack; +protected: + void broadcast(const Signal &) const; +public: + Broadcaster(int log = 3) : listenerStack(log) {} + void add(const Listener<Signal> &); + void remove(const Listener<Signal> &); +}; + +template <class Host, class Signal> +class ListenerFor : public Listener<Signal> { +private: + Host *host; + void (Host::*handler)(const Signal &); +public: + ListenerFor(Host *t, void (Host::*h)(const Signal &)) + : host(t), handler(h) {} + ListenerFor(const ListenerFor<Host, Signal> &x) + : host(x.host), handler(x.handler) {} + void handle(const Signal &s) { (host->*handler)(s); } + int operator == (const Listener<Signal> &r) const { + const ListenerFor<Host,Signal> &rf = (const ListenerFor<Host,Signal> &) r; + return (host == rf.host && handler == rf.handler); + } + int operator < (const Listener<Signal> &r) const { + const ListenerFor<Host,Signal> &rf = (const ListenerFor<Host,Signal> &) r; + return host == rf.host ? &handler < &rf.handler : host < rf.host; + } + ListenerFor<Host,Signal> *copy() const { + return new ListenerFor<Host,Signal>(host, handler); + } +}; + +template <class Signal> +void Broadcaster<Signal>::add(const Listener<Signal> &s) { + int n = listenerStack.size(); + int i; + for (i = 0; i < n; i++) { + if (s == *listenerStack[i]) { + return; + } + } + listenerStack.push(s.copy()); +} + +template <class Signal> +void Broadcaster<Signal>::remove(const Listener<Signal> &s) { + int n = listenerStack.size(); + int i; + for (i = 0; i < n; i++) { + if (s == *listenerStack[i]) { + break; + } + } + if (i == n) { + return; + } + delete listenerStack[i]; + while (++i < n) { + listenerStack[i-1] = listenerStack[i]; + } + listenerStack.pop(); +} + +template <class Signal> +void Broadcaster<Signal>::broadcast(const Signal &s) const { + int n = listenerStack.size(); + int i; + for (i = 0; i < n; i++) { + listenerStack[i]->handle(s); + } +} + +template <class Host, class Signal> +void connect(Host *host, void (Host::*handler)(const Signal &), + Broadcaster<Signal> &broadcaster) { + broadcaster.add(ListenerFor<Host,Signal>(host, handler)); +} + +template <class Host, class Signal> +void disconnect(Host *host, void (Host::*handler)(const Signal &), + Broadcaster<Signal> &broadcaster) { + broadcaster.remove(ListenerFor<Host,Signal>(host, handler)); +} + +template <class Signal> +class Responder { +public: + virtual void handle(Signal &) = 0; + virtual int operator == (const Responder<Signal> &p) const = 0; + virtual int operator == (const Responder<Signal> *p) const { + return *p == *this; + } + virtual Responder<Signal> *copy() const = 0; +}; + +template <class Signal> +class Requester { +private: + AgStack<Responder<Signal> *> responderStack; + int level; + +protected: + void request(Signal &); + +public: + Requester() : responderStack(3), level(0) {} + void add(const Responder<Signal> &r) { + responderStack.push(r.copy()); + level++; + } + void add(Responder<Signal> *r) { + responderStack.push(r); + level++; + } + void remove(const Responder<Signal> &); + Responder<Signal> *pop() { return responderStack.pop(); } +}; + +template <class Host, class Signal> +class ResponderFor : public Responder<Signal> { +private: + Host *host; + void (Host::*handler)(Signal &); + +public: + ResponderFor(Host *t, void (Host::*h)(Signal &)) : host(t), handler(h) {} + void handle(Signal &s) { (host->*handler)(s); } + int operator == (const Responder<Signal> &r) const { + const ResponderFor<Host,Signal> &rf = + (const ResponderFor<Host,Signal> &) r; + return (host == rf.host && handler == rf.handler); + } + Responder<Signal> *copy() const { + return new ResponderFor<Host,Signal>(host, handler); + } +}; + +template <class Signal> +void Requester<Signal>::remove(const Responder<Signal> &s) { + int n = responderStack.size(); + int i; + for (i = 0; i < n; i++) { + if (s == responderStack[i]) { + break; + } + } + if (i == n) { + return; + } + delete responderStack[i]; + if (level >= i) { + level--; + } + while (++i < n) { + responderStack[i-1] = responderStack[i]; + } + responderStack.pop(); +} + +template <class Signal> +void Requester<Signal>::request(Signal &s) { + assert(level > 0); + level--; + responderStack[level]->handle(s); + level++; +} + +template <class Host, class Signal> +void connect(Host *host, void (Host::*handler)(Signal &), + Requester<Signal> &requester) { + requester.add(ResponderFor<Host,Signal>(host, handler)); +} + +template <class Host, class Signal> +void disconnect(Host *host, void (Host::*handler)(Signal &), + Requester<Signal> &requester) { + requester.add(ResponderFor<Host,Signal>(host, handler)); +} + +template <class Signal> +void reroute(Requester<Signal> &from, Requester<Signal> &to) { + to.add(from.pop()); +} + + +#endif /* AGSIGNAL_H */