00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00056 #include "common/test/run.hpp"
00057 #include "common/singleton.hpp"
00058
00059 #include <boost/format.hpp>
00060 #include <iostream>
00061 #include <vector>
00062
00063 using lumiera::Singleton;
00064 using boost::format;
00065 using std::string;
00066 using std::cout;
00067
00068
00069 namespace lumiera
00070 {
00071 namespace visitor_concept_draft
00072 {
00073
00074
00075
00076
00077 template<class TOOL> class Tag;
00078
00079
00080 template<class TOOL, class TOOLImpl>
00081 struct TagTypeRegistry
00082 {
00083 static Tag<TOOL> tag;
00084 };
00085
00086
00087 template<class TOOL>
00088 class Tag
00089 {
00090 size_t tagID;
00091 static size_t lastRegisteredID;
00092
00093 public:
00094 Tag() : tagID(0) { }
00095 operator size_t() const { return tagID; }
00096
00097
00098 template<class TOOLImpl>
00099 static Tag&
00100 get (TOOLImpl* const concreteTool=0)
00101 {
00102
00103 Tag& t = TagTypeRegistry<TOOL,TOOLImpl>::tag;
00104 if (!t)
00105 t.tagID = ++lastRegisteredID;
00106 return t;
00107 }
00108
00109 };
00110
00111
00112
00114 template<class TOOL, class TOOLImpl>
00115 Tag<TOOL> TagTypeRegistry<TOOL,TOOLImpl>::tag;
00116
00117 template<class TOOL>
00118 size_t Tag<TOOL>::lastRegisteredID (0);
00119
00120
00121
00122
00123
00124
00126 template<typename RET>
00127 class Tool
00128 {
00129 public:
00130 typedef RET ReturnType;
00131 typedef Tool<RET> ToolBase;
00132
00133 virtual ~Tool () { };
00134
00137 virtual Tag<ToolBase> getTag() = 0;
00138 };
00139
00140
00142 template<class TOOLImpl, class BASE=Tool<void> >
00143 class ToolType : public BASE
00144 {
00145 typedef typename BASE::ToolBase ToolBase;
00146
00147 public:
00148 virtual Tag<ToolBase> getTag()
00149 {
00150 TOOLImpl* typeref = 0;
00151 return Tag<ToolBase>::get (typeref);
00152 }
00153 };
00154
00155
00156
00157
00163 template<class TAR, class TOOL>
00164 class Dispatcher
00165 {
00166 typedef typename TOOL::ReturnType ReturnType;
00167
00173 template<class TOOLImpl>
00174 static ReturnType
00175 callTrampoline (TAR& obj, TOOL& tool)
00176 {
00177
00178 REQUIRE (INSTANCEOF (TOOLImpl, &tool));
00179 TOOLImpl& toolObj = static_cast<TOOLImpl&> (tool);
00180
00181
00182
00183
00184 return toolObj.treat (obj);
00185 }
00186
00187 typedef ReturnType (*Trampoline) (TAR&, TOOL& );
00188
00189
00191 std::vector<Trampoline> table_;
00192
00193
00194 inline bool
00195 is_known (size_t id)
00196 {
00197 return id<=table_.size() && table_[id-1];
00198 }
00199
00200 inline void
00201 storePtr (size_t id, Trampoline func)
00202 {
00203
00204 if (id>table_.size())
00205 table_.resize (id);
00206 table_[id-1] = func;
00207 }
00208
00209 inline Trampoline
00210 storedTrampoline (size_t id)
00211 {
00212 if (id<=table_.size() && table_[id-1])
00213 return table_[id-1];
00214 else
00215 return &errorHandler;
00216 }
00217
00218 static ReturnType
00219 errorHandler (TAR&, TOOL&)
00220 {
00221 cout << "Error Handler: unregistered combination of (Tool, TargetObject) invoked!\n";
00222 }
00223
00224
00225 public:
00226 static Singleton<Dispatcher<TAR,TOOL> > instance;
00227
00228 inline ReturnType
00229 forwardCall (TAR& target, TOOL& tool)
00230 {
00231
00232 Tag<TOOL> index = tool.getTag();
00233 return (*storedTrampoline(index)) (target, tool);
00234 }
00235
00236 template<class TOOLImpl>
00237 inline void
00238 enroll(TOOLImpl* typeref)
00239 {
00240 Tag<TOOL>& index = Tag<TOOL>::get (typeref);
00241 if (is_known (index))
00242 return;
00243 else
00244 {
00245 Trampoline func = &callTrampoline<TOOLImpl>;
00246 storePtr (index, func);
00247 }
00248
00249 }
00250 };
00251
00253 template<class TAR, class TOOL>
00254 Singleton<Dispatcher<TAR,TOOL> > Dispatcher<TAR,TOOL>::instance;
00255
00256
00257
00258
00259
00265 template<class TAR, class TOOLImpl, class BASE=Tool<void> >
00266 class Applicable
00267 {
00268 typedef typename BASE::ReturnType Ret;
00269 typedef typename BASE::ToolBase ToolBase;
00270
00271 protected:
00272 Applicable ()
00273 {
00274 TOOLImpl* typeref = 0;
00275 Dispatcher<TAR,ToolBase>::instance().enroll (typeref);
00276 }
00277
00278 virtual ~Applicable () {}
00279
00280 public:
00281
00282
00283
00284
00285 };
00286
00287
00288
00289
00290
00293 template
00294 < class TOOL = Tool<void>
00295 >
00296 class Visitable
00297 {
00298 protected:
00299 virtual ~Visitable () { };
00300
00302 typedef typename TOOL::ToolBase ToolBase;
00303 typedef typename TOOL::ReturnType ReturnType;
00304
00310 template <class TAR>
00311 static inline ReturnType
00312 dispatchOp (TAR& target, TOOL& tool)
00313 {
00314 return Dispatcher<TAR,ToolBase>::instance().forwardCall (target,tool);
00315 }
00316
00317 public:
00320 virtual ReturnType apply (TOOL&) = 0;
00321 };
00322
00323
00328 #define DEFINE_PROCESSABLE_BY(TOOL) \
00329 virtual ReturnType apply (TOOL& tool) \
00330 { return dispatchOp (*this, tool); }
00331
00332
00333
00334
00335
00336
00337
00338
00339 namespace test
00340 {
00341
00342 typedef Tool<void> VisitingTool;
00343
00344 class HomoSapiens : public Visitable<>
00345 {
00346 public:
00347 DEFINE_PROCESSABLE_BY (VisitingTool);
00348 };
00349
00350 class Boss : public HomoSapiens
00351 {
00352 public:
00353 DEFINE_PROCESSABLE_BY (VisitingTool);
00354 };
00355
00356 class BigBoss : public Boss
00357 {
00358 public:
00359 DEFINE_PROCESSABLE_BY (VisitingTool);
00360 };
00361
00362 class Leader : public Boss
00363 {
00364 };
00365
00366 class Visionary : public Leader
00367 {
00368 };
00369
00370
00371 class VerboseVisitor
00372 : public VisitingTool
00373 {
00374 protected:
00375 void talk_to (string guy)
00376 {
00377 cout << format ("Hello %s, nice to meet you...\n") % guy;
00378 }
00379 };
00380
00381
00382 class Babbler
00383 : public Applicable<Boss,Babbler>,
00384 public Applicable<BigBoss,Babbler>,
00385 public Applicable<Visionary,Babbler>,
00386 public ToolType<Babbler, VerboseVisitor>
00387 {
00388 public:
00389 void treat (Boss&) { talk_to("Boss"); }
00390 void treat (BigBoss&) { talk_to("Big Boss"); }
00391
00392 };
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411 class VisitingTool_concept : public Test
00412 {
00413 virtual void run(Arg arg)
00414 {
00415 known_visitor_known_class();
00416 visitor_not_visiting_some_class();
00417 }
00418
00419 void known_visitor_known_class()
00420 {
00421 Boss x1;
00422 BigBoss x2;
00423
00424
00425 HomoSapiens& homo1 (x1);
00426 HomoSapiens& homo2 (x2);
00427
00428 cout << "=== Babbler meets Boss and BigBoss ===\n";
00429 Babbler bab;
00430 VisitingTool& vista (bab);
00431 homo1.apply (vista);
00432 homo2.apply (vista);
00433 }
00434
00435 void visitor_not_visiting_some_class()
00436 {
00437 HomoSapiens x1;
00438 Visionary x2;
00439
00440 HomoSapiens& homo1 (x1);
00441 HomoSapiens& homo2 (x2);
00442
00443 cout << "=== Babbler meets HomoSapiens and Visionary ===\n";
00444 Babbler bab;
00445 VisitingTool& vista (bab);
00446 homo1.apply (vista);
00447 homo2.apply (vista);
00448 }
00449
00450 };
00451
00452
00454 LAUNCHER (VisitingTool_concept, "unit common");
00455
00456
00457
00458 }
00459
00460 }
00461
00462 }