view anagram/support/agsignal.h @ 17:12171da8943f

Don't refer to CVS.
author David A. Holland
date Tue, 31 May 2022 01:56:37 -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 */