00001
00002
00003 #ifndef DOUBLE_DISPATCH_H
00004 #define DOUBLE_DISPATCH_H
00005
00006 #include "typemap.h"
00007 #include "ObjectRef.h"
00008 #include "BaseException.h"
00009
00010
00011 #include <map>
00012
00013
00014
00015
00016 namespace FD {
00017
00018 class DoubleDispatch;
00019
00020 class DoubleDispatchException : public BaseException {
00021 protected:
00022 DoubleDispatch *table;
00023 std::string type1, type2;
00024 public:
00025 DoubleDispatchException(DoubleDispatch *_table, std::string _type1, std::string _type2);
00026 virtual void print(std::ostream &out = std::cerr);
00027
00028 };
00029
00030
00031 class DoubleDispatch {
00032 public:
00033 typedef ObjectRef (*funct_ptr) (ObjectRef x, ObjectRef y);
00034
00035 protected:
00036 std::string name;
00037
00038
00039
00040
00041 typedef TypeMap<funct_ptr> vtable1Type;
00042 typedef TypeMap<vtable1Type> vtable2Type;
00043
00044
00045
00046
00047 vtable2Type vtable;
00048
00049 public:
00050 DoubleDispatch(std::string _name) : name(_name) {}
00051
00052 const std::string &getName() {return name;}
00053
00054 void registerFunct(funct_ptr ptr, const std::type_info *x, const std::type_info *y)
00055 {
00056 vtable[x][y] = ptr;
00057 }
00058
00059 ObjectRef call(ObjectRef x, ObjectRef y)
00060 {
00061 const std::type_info *t1 = &typeid(*x);
00062 const std::type_info *t2 = &typeid(*y);
00063 vtable2Type::iterator v1 = vtable.find(t1);
00064 if (v1!=vtable.end())
00065 {
00066 vtable1Type::iterator v2 = v1->second.find(t2);
00067 if (v2!=v1->second.end())
00068 {
00069 return v2->second(x,y);
00070 } else {
00071 throw new DoubleDispatchException(this, t1->name(), t2->name());
00072 }
00073 } else {
00074 throw new DoubleDispatchException(this, t1->name(), t2->name());
00075 }
00076 }
00077 };
00078
00079
00080 #define DEFINE_DOUBLE_VTABLE(klass) class klass { \
00081 public: \
00082 static DoubleDispatch &vtable() {static DoubleDispatch table(# klass); return table;} \
00083 static ObjectRef perform(ObjectRef x, ObjectRef y) \
00084 { \
00085 return vtable().call(x,y); \
00086 } \
00087 static int reg(DoubleDispatch::funct_ptr ptr, const std::type_info *x, const std::type_info *y) \
00088 { \
00089 vtable().registerFunct(ptr,x,y); \
00090 return 0; \
00091 } \
00092 };
00093
00094 #define REGISTER_DOUBLE_VTABLE(klass, func, type1, type2) \
00095 int dummy_vtable_init_for ## klass ## _ ## func =\
00096 klass::reg(func, &typeid(type1), &typeid(type2));
00097
00098
00099 #define REGISTER_DOUBLE_VTABLE_TEMPLATE(klass, func, type1, type2, type3, id) \
00100 int dummy_vtable_init_for ## klass ## func ## _ ## id =\
00101 klass::reg(func<type1,type2,type3>, &typeid(type1), &typeid(type2));
00102
00103 }
00104 #endif