view anagram/guisupport/action.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 1997-2002 Parsifal Software. All Rights Reserved.
 * See the file COPYING for license and usage terms.
 *
 * action.h
 */

#ifndef ACTION_H
#define ACTION_H

#include "agstack.h"


class AgAction {
public:

  class Kernel {
  private:
    int useCount;
  public:
    virtual ~Kernel() {}
    virtual void perform() const = 0;
    
    Kernel() : useCount(0) {}
    void lock() { useCount++; }
    int unlock() { return --useCount <= 0; }
  };

protected:
  Kernel *kernel;
  static int running;

  static AgStack<AgAction> startupStack;

public:
  AgAction() : kernel(0) {}
  AgAction(AgAction::Kernel *kernel_) : kernel(kernel_) {
    if (kernel) {
      kernel->lock();
    }
  }
  AgAction(const AgAction &a) : kernel(a.kernel) {
    if (kernel) {
      kernel->lock();
    }
  }
  AgAction &operator = (const AgAction &a) {
    if (kernel && kernel->unlock()) {
      delete kernel;
    }
    kernel = a.kernel;
    if (kernel) {
      kernel->lock();
    }
    return *this;
  }
  ~AgAction() {
    if (kernel && kernel->unlock()) {
      delete kernel;
      kernel = 0;
    }
  }
  int exists() { return kernel != 0; }
  void perform() const { if (kernel) kernel->perform(); }
  void operator () () const { if (kernel) kernel->perform(); }
  //void defer() const;
  void performDeferred() const;
  static void startup();
  int operator < (const AgAction &a) const { return this < &a; }
};


template<class T>
class AgClassAction : public AgAction {
private:

  class Kernel : public AgAction::Kernel {
  private:
    T &object;
    void (T:: * memberFunction)();

  public:
    Kernel(T &object_, void (T:: * memberFunction_)()) :
      object(object_) ,
      memberFunction(memberFunction_)
    {}
    void perform() const {(object.*memberFunction)();}
  };

public:
  AgClassAction(T &object_, void (T:: * memberFunction_)()) :
    AgAction(new AgClassAction<T>::Kernel(object_,memberFunction_))
  {}
  AgClassAction(const AgClassAction<T> &a) :
    AgAction(a)
  {}
};

template <class T>
AgAction actionObject(T *t, void (T:: * memberFunction)()) {
  return AgClassAction<T>(*t, memberFunction);
}

void defer(void (*f)());

template <class T>
void defer(T *t, void (T:: * memberFunction)()) {
  AgClassAction<T>(*t, memberFunction).performDeferred();
}

class AgSimpleAction : public AgAction {
private:

  class Kernel : public AgAction::Kernel {
    void (* function)();
  public:
    Kernel(void (* function_)()) :
      function(function_)
    {}
    void perform() const {(*function)();}
  };

public:
  AgSimpleAction(void (* function_)()) :
    AgAction(new AgSimpleAction::Kernel(function_))
  {}
  AgSimpleAction(const AgSimpleAction &a) :
    AgAction(a)
  {}
};

AgAction actionObject(void (* function)());


////////////////////////////////////////////////////////////
//
// interaction with GUI event loop

// this must be provided by the GUI - see e.g. vaclgui/actionwin.cpp
// (not defined in action.cpp)
void AgActionEnqueueInGui(AgAction::Kernel *kernel);

// and the GUI should hand the object back to this function.
void AgActionDispatchFromGui(AgAction::Kernel *kernel);


#endif /* ACTION_H */