Mercurial > ~dholland > hg > ag > index.cgi
view anagram/support/agsignal.h @ 12:aab9ff6af791
Strengthen the build hack for non-DOS targets.
author | David A. Holland |
---|---|
date | Tue, 31 May 2022 00:58:42 -0400 |
parents | 13d2b8934445 |
children |
line wrap: on
line source
/* * 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 */