Source: data-flow/include/DoubleDispatch.h


Annotated List
Files
Globals
Hierarchy
Index
// Copyright (C) 1999 Jean-Marc Valin

#ifndef DOUBLE_DISPATCH_H
#define DOUBLE_DISPATCH_H

#include "typemap.h"
#include "ObjectRef.h"
#include "BaseException.h"

//#ifdef NO_HASH_MAP
#include <map>
//#else
//#include <hash_map>
//#endif

class DoubleDispatch;

class DoubleDispatchException : public BaseException {
  protected:
   DoubleDispatch *table;
   string type1, type2;
  public:
   DoubleDispatchException(DoubleDispatch *_table, string _type1, string _type2);
   virtual void print(ostream &out = cerr);
   
};

//template<class T, class U>
class DoubleDispatch {
  public:
   typedef ObjectRef (*funct_ptr) (ObjectRef x, ObjectRef y);

  protected:
   string name;
//#ifdef NO_HASH_MAP
   //typedef map<const type_info *, funct_ptr> vtable1Type;
   //typedef map<const type_info *, vtable1Type > vtable2Type;

   typedef TypeMap<funct_ptr> vtable1Type;
   typedef TypeMap<vtable1Type> vtable2Type;
//#else
//   typedef hash_map<const type_info *, funct_ptr> vtable1Type;
//   typedef hash_map<const type_info *, vtable1Type > vtable2Type;
//#endif
   vtable2Type vtable;

  public:
   DoubleDispatch(string _name) : name(_name) {}

   const string &getName() {return name;}

   void registerFunct(funct_ptr ptr, const type_info *x, const type_info *y)
   {
      vtable[x][y] = ptr;
   }

   ObjectRef call(ObjectRef x, ObjectRef y)
   {
      const type_info *t1 = &typeid(*x);
      const type_info *t2 = &typeid(*y);
      vtable2Type::iterator v1 = vtable.find(t1);
      if (v1!=vtable.end())
      {
	 vtable1Type::iterator v2 = v1->second.find(t2);
	 if (v2!=v1->second.end())
	 {
	    return v2->second(x,y);
	 } else {
	    throw new DoubleDispatchException(this, t1->name(), t2->name());
	 }
      } else {
	 throw new DoubleDispatchException(this, t1->name(), t2->name());
      }
   }
};


#define DEFINE_DOUBLE_VTABLE(klass) class klass {                                   \
  public:                                                                           \
   static DoubleDispatch &vtable() {static DoubleDispatch table(# klass); return table;}     \
   static ObjectRef perform(ObjectRef x, ObjectRef y)                               \
   {                                                                                \
      return vtable().call(x,y);                                                    \
   }                                                                                \
   static int reg(DoubleDispatch::funct_ptr ptr, const type_info *x, const type_info *y) \
   {                                                                                \
      vtable().registerFunct(ptr,x,y);                                              \
      return 0;                                                                     \
   }                                                                                \
};

#define REGISTER_DOUBLE_VTABLE(klass, func, type1, type2) \
        int dummy_vtable_init_for ## klass ## _ ## func =\
        klass::reg(func, &typeid(type1), &typeid(type2));

#endif

Generated by: jmvalin@usw-pr-shell2 on Mon Jun 24 00:06:36 2002, using kdoc 2.0a40.