00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef LUMIERA_VISITORDISPATCHER_H
00026 #define LUMIERA_VISITORDISPATCHER_H
00027
00028 #include "common/error.hpp"
00029 #include "common/util.hpp"
00030 #include "common/singleton.hpp"
00031 #include "common/multithread.hpp"
00032
00033 #include <vector>
00034
00035
00036 namespace lumiera
00037 {
00038 namespace visitor
00039 {
00040
00041 template<class TOOL> class Tag;
00042
00043
00044 template<class TOOL, class TOOLImpl>
00045 struct TagTypeRegistry
00046 {
00047 static Tag<TOOL> tag;
00048 };
00049
00055 template<class TOOL>
00056 class Tag
00057 {
00058 size_t tagID;
00059 static size_t lastRegisteredID;
00060
00061 private:
00062 static void
00063 generateID (size_t& id)
00064 {
00065 Thread::Lock<Tag> guard SIDEEFFECT;
00066 if (!id)
00067 id = ++lastRegisteredID;
00068 }
00069
00070 public:
00071 Tag() : tagID(0) { }
00072 operator size_t() const { return tagID; }
00073
00074
00075 template<class TOOLImpl>
00076 static Tag&
00077 get (TOOLImpl* const concreteTool=0)
00078 {
00079 Tag& t = TagTypeRegistry<TOOL,TOOLImpl>::tag;
00080 if (!t) generateID (t.tagID);
00081 return t;
00082 }
00083
00084 };
00085
00086
00087
00089 template<class TOOL, class TOOLImpl>
00090 Tag<TOOL> TagTypeRegistry<TOOL,TOOLImpl>::tag;
00091
00092 template<class TOOL>
00093 size_t Tag<TOOL>::lastRegisteredID (0);
00094
00095
00096
00097
00098
00099
00100
00101
00107 template<class TAR, class TOOL>
00108 class Dispatcher
00109 {
00110 typedef typename TOOL::ReturnType ReturnType;
00111
00117 template<class TOOLImpl>
00118 static ReturnType
00119 callTrampoline (TAR& obj, TOOL& tool)
00120 {
00121
00122 REQUIRE (INSTANCEOF (TOOLImpl, &tool));
00123 TOOLImpl& toolObj = static_cast<TOOLImpl&> (tool);
00124
00125
00126
00127
00128 return toolObj.treat (obj);
00129 }
00130
00131 typedef ReturnType (*Trampoline) (TAR&, TOOL& );
00132
00133
00135 std::vector<Trampoline> table_;
00136
00137
00138 void
00139 accomodate (size_t index)
00140 {
00141 Thread::Lock<Dispatcher> guard SIDEEFFECT;
00142 if (index > table_.size())
00143 table_.resize (index);
00144 }
00145
00146 inline bool
00147 is_known (size_t id)
00148 {
00149 return id<=table_.size() && table_[id-1];
00150 }
00151
00152 inline void
00153 storePtr (size_t id, Trampoline func)
00154 {
00155 REQUIRE (func);
00156 REQUIRE (0 < id);
00157 if (id>table_.size())
00158 accomodate (id);
00159 table_[id-1] = func;
00160 }
00161
00162 inline Trampoline
00163 storedTrampoline (size_t id)
00164 {
00165 if (id<=table_.size() && table_[id-1])
00166 return table_[id-1];
00167 else
00168 return &errorHandler;
00169 }
00170
00171 static ReturnType
00172 errorHandler (TAR& target, TOOL& tool)
00173 {
00174 return tool.onUnknown (target);
00175 }
00176
00177
00178 public:
00179 static Singleton<Dispatcher<TAR,TOOL> > instance;
00180
00181 inline ReturnType
00182 forwardCall (TAR& target, TOOL& tool)
00183 {
00184
00185 Tag<TOOL> index = tool.getTag();
00186 return (*storedTrampoline(index)) (target, tool);
00187 }
00188
00189 template<class TOOLImpl>
00190 inline void
00191 enroll(TOOLImpl* typeref)
00192 {
00193 Tag<TOOL>& index = Tag<TOOL>::get (typeref);
00194 if (is_known (index))
00195 return;
00196 else
00197 {
00198 Trampoline func = &callTrampoline<TOOLImpl>;
00199 storePtr (index, func);
00200 }
00201
00202 }
00203 };
00204
00206 template<class TAR, class TOOL>
00207 Singleton<Dispatcher<TAR,TOOL> > Dispatcher<TAR,TOOL>::instance;
00208
00209
00210
00211
00212 }
00213
00214 }
00215 #endif