view anagram/support/agsignal.h @ 21:1c9dac05d040

Add lint-style FALLTHROUGH annotations to fallthrough cases. (in the parse engine and thus the output code) Document this, because the old output causes warnings with gcc10.
author David A. Holland
date Mon, 13 Jun 2022 00:04:38 -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 */