FortranInstance

InstanceWrapper

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
#ifndef gen_FortranInstance_h
#define gen_FortranInstance_h

#include <string>

namespace gen {

  // the callbacks from Pythia6/Herwig6 which are passed to the FortranInstance
  extern "C" {
  void upinit_();
  void upevnt_();
  void upveto_(int *);
  }

  class FortranInstance {
  public:
    FortranInstance() : instanceNesting(0) {}
    virtual ~FortranInstance() noexcept(false);

    void call(void (&fn)()) {
      InstanceWrapper wrapper(this);
      fn();
    }
    template <typename T>
    T call(T (&fn)()) {
      InstanceWrapper wrapper(this);
      return fn();
    }
    template <typename A>
    void call(void (&fn)(A), A a) {
      InstanceWrapper wrapper(this);
      fn(a);
    }
    template <typename T, typename A>
    T call(T (&fn)(A), A a) {
      InstanceWrapper wrapper(this);
      return fn(a);
    }
    template <typename A1, typename A2>
    void call(void (&fn)(A1, A2), A1 a1, A2 a2) {
      InstanceWrapper wrapper(this);
      fn(a1, a2);
    }
    template <typename T, typename A1, typename A2>
    T call(T (&fn)(A1, A2), A1 a1, A2 a2) {
      InstanceWrapper wrapper(this);
      return fn(a1, a2);
    }

    // if a member is instantiated at the beginning of a method,
    // it makes sure this FortranInstance instance is kept as
    // current instance during the execution of the method
    // This wrapper makes the enter()..leave() cycle exception-safe
    struct InstanceWrapper {
      InstanceWrapper(FortranInstance *instance) {
        this->instance = instance;
        instance->enter();
      }

      ~InstanceWrapper() { instance->leave(); }

      FortranInstance *instance;
    };

    // set this instance to be the current one
    // will throw exception when trying to reenter Herwig twice
    virtual void enter();

    // leave instance
    // will throw if the currently running instance does not match
    virtual void leave();

    // get the currently running instance (from enterInstance)
    // intended for callbacks from Fortran
    template <typename T>
    static T *getInstance() {
      T *instance = dynamic_cast<T *>(currentInstance);
      if (!instance)
        throwMissingInstance();
      return instance;
    }

    // Fortran callbacks
    virtual void upInit();
    virtual void upEvnt();
    virtual bool upVeto();

    static const std::string kFortranInstance;

  private:
    // list all the Fortran callbacks here
    friend void gen::upinit_();
    friend void gen::upevnt_();
    friend void gen::upveto_(int *);

    // internal methods
    static void throwMissingInstance();

    // how many times enter() was called
    // this is to make sure leave() will release the instance
    // after the same number of calls
    // nesting can in theory occur if the Fortran callback calls
    // into Herwig again
    int instanceNesting;

    // this points to the Herwig instance that is currently being executed
    static FortranInstance *currentInstance;
  };

}  // namespace gen

#endif  // gen_FortranInstance_h