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 */