Lumiera  0.pre.03
»edit your freedom«
visitingtool-concept.cpp
Go to the documentation of this file.
1 /*
2  VisitingTool(Concept) - concept draft of a Visitor library implementation
3 
4  Copyright (C)
5  2008, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 * *****************************************************************/
13 
14 
47 #include "lib/test/run.hpp"
48 #include "lib/format-cout.hpp"
49 #include "lib/format-string.hpp"
50 #include "lib/depend.hpp"
51 
52 #include <vector>
53 
54 using util::_Fmt;
55 using std::string;
56 
57 
58 namespace lumiera {
59  namespace visitor_concept_draft {
60 
61  // ================================================================== Library ====
62 
63 
64 
65  template<class TOOL> class Tag;
66 
67 
68  template<class TOOL, class TOOLImpl>
70  {
71  static Tag<TOOL> tag;
72  };
73 
74 
75  template<class TOOL>
76  class Tag
77  {
78  size_t tagID;
79  static size_t lastRegisteredID;
80 
81  public:
82  Tag() : tagID(0) { }
83  operator size_t() const { return tagID; }
84 
85 
86  template<class TOOLImpl>
87  static Tag&
88  get (TOOLImpl* const =0) // param used to pass type info
89  {
90  // we have a race condition here...
92  if (!t)
93  t.tagID = ++lastRegisteredID;
94  return t;
95  }
96 
97  };
98 
99 
100 
102  template<class TOOL, class TOOLImpl>
104 
105  template<class TOOL>
106  size_t Tag<TOOL>::lastRegisteredID (0);
107 
108 
109 
110 
111 
112 
114  template<typename RET>
115  class Tool
116  {
117  public:
118  typedef RET ReturnType;
119  typedef Tool<RET> ToolBase;
120 
121  virtual ~Tool() { };
122 
125  virtual Tag<ToolBase> getTag() =0;
126  };
127 
128 
130  template<class TOOLImpl, class BASE =Tool<void>>
131  class ToolType
132  : public BASE
133  {
134  typedef typename BASE::ToolBase ToolBase;
135 
136  public:
137  virtual Tag<ToolBase>
138  getTag()
139  {
140  TOOLImpl* typeKey = 0;
141  return Tag<ToolBase>::get (typeKey);
142  }
143  };
144 
145 
146 
147 
153  template<class TAR, class TOOL>
155  {
156  typedef typename TOOL::ReturnType ReturnType;
157 
163  template<class TOOLImpl>
164  static ReturnType
165  callTrampoline (TAR& obj, TOOL& tool)
166  {
167  // cast down to real implementation type
168  CHECK (INSTANCEOF (TOOLImpl, &tool));
169  TOOLImpl& toolObj = static_cast<TOOLImpl&> (tool);
170 
171  // trigger (compile time) overload resolution
172  // based on concrete type, then dispatch the call.
173  // Note this may cause obj to be upcasted.
174  return toolObj.treat (obj);
175  }
176 
177  typedef ReturnType (*Trampoline) (TAR&, TOOL& );
178 
179 
181  std::vector<Trampoline> table_;
182 
183 
184  inline bool
185  is_known (size_t id)
186  {
187  return id<=table_.size() && table_[id-1];
188  }
189 
190  inline void
191  storePtr (size_t id, Trampoline func)
192  {
193  // lacks error- and concurrency handling....
194  if (id>table_.size())
195  table_.resize (id);
196  table_[id-1] = func;
197  }
198 
199  inline Trampoline
200  storedTrampoline (size_t id)
201  {
202  if (id<=table_.size() && table_[id-1])
203  return table_[id-1];
204  else
205  return &errorHandler;
206  }
207 
208  static ReturnType
209  errorHandler (TAR&, TOOL&)
210  {
211  cout << "Error Handler: unregistered combination of (Tool, TargetObject) invoked!\n";
212  }
213 
214 
215  public:
217 
218  inline ReturnType
219  forwardCall (TAR& target, TOOL& tool)
220  {
221  // get concrete type via tool's VTable
222  Tag<TOOL> index = tool.getTag();
223  return (*storedTrampoline(index)) (target, tool);
224  }
225 
226  template<class TOOLImpl>
227  inline void
228  enrol (TOOLImpl* typeKey)
229  {
230  Tag<TOOL>& index = Tag<TOOL>::get (typeKey);
231  if (is_known (index))
232  return;
233  else
234  {
235  Trampoline func = &callTrampoline<TOOLImpl>;
236  storePtr (index, func);
237  }
238 
239  }
240  };
241 
243  template<class TAR, class TOOL>
245 
246 
247 
248 
249 
255  template<class TAR, class TOOLImpl, class BASE=Tool<void> >
257  {
258  typedef typename BASE::ReturnType Ret;
259  typedef typename BASE::ToolBase ToolBase;
260 
261  protected:
262  Applicable()
263  {
264  TOOLImpl* typeKey = 0;
265  Dispatcher<TAR,ToolBase>::instance().enrol (typeKey);
266  }
267 
268  virtual ~Applicable () {}
269 
270  public:
271  // we could enforce the definition of treat()-functions by:
272  //
273  // virtual Ret treat (TAR& target) = 0;
274 
275  };
276 
277 
278 
279 
280 
283  template
284  < class TOOL = Tool<void>
285  >
286  class Visitable
287  {
288  protected:
289  virtual ~Visitable() { };
290 
292  typedef typename TOOL::ToolBase ToolBase;
293  typedef typename TOOL::ReturnType ReturnType;
294 
300  template <class TAR>
301  static inline ReturnType
302  dispatchOp (TAR& target, TOOL& tool)
303  {
304  return Dispatcher<TAR,ToolBase>::instance().forwardCall (target,tool);
305  }
306 
307  public:
310  virtual ReturnType apply (TOOL&) = 0;
311  };
312 
313 
318 #define DEFINE_PROCESSABLE_BY(TOOL) \
319  virtual ReturnType apply (TOOL& tool) \
320  { return dispatchOp (*this, tool); }
321 
322 
323  // =============================================================(End) Library ====
324 
325 
326 
327 
328 
329  namespace test {
330 
331  typedef Tool<void> VisitingTool;
332 
333  class HomoSapiens : public Visitable<>
334  {
335  public:
336  DEFINE_PROCESSABLE_BY (VisitingTool);
337  };
338 
339  class Boss : public HomoSapiens
340  {
341  public:
342  DEFINE_PROCESSABLE_BY (VisitingTool);
343  };
344 
345  class BigBoss : public Boss
346  {
347  public:
348  DEFINE_PROCESSABLE_BY (VisitingTool);
349  };
350 
351  class Leader : public Boss
352  {
353  };
354 
355  class Visionary : public Leader
356  {
357  };
358 
359 
361  : public VisitingTool
362  {
363  protected:
364  void talk_to (string guy)
365  {
366  cout << _Fmt{"Hello %s, nice to meet you...\n"} % guy;
367  }
368  };
369 
370 
371  class Babbler
372  : public Applicable<Boss,Babbler>,
373  public Applicable<BigBoss,Babbler>,
374  public Applicable<Visionary,Babbler>,
375  public ToolType<Babbler, VerboseVisitor>
376  {
377  public:
378  void treat (Boss&) { talk_to("Boss"); }
379  void treat (BigBoss&) { talk_to("Big Boss"); }
380 
381  };
382 
383 
384 
385 
386 
387 
388 
389  /*********************************************************************/
400  class VisitingTool_concept : public Test
401  {
402  virtual void run(Arg)
403  {
404  known_visitor_known_class();
405  visitor_not_visiting_some_class();
406  }
407 
408  void known_visitor_known_class()
409  {
410  Boss x1;
411  BigBoss x2;
412 
413  // masquerade as HomoSapiens...
414  HomoSapiens& homo1 (x1);
415  HomoSapiens& homo2 (x2);
416 
417  cout << "=== Babbler meets Boss and BigBoss ===\n";
418  Babbler bab;
419  VisitingTool& vista (bab);
420  homo1.apply (vista);
421  homo2.apply (vista);
422  }
423 
424  void visitor_not_visiting_some_class()
425  {
426  HomoSapiens x1;
427  Visionary x2;
428 
429  HomoSapiens& homo1 (x1);
430  HomoSapiens& homo2 (x2);
431 
432  cout << "=== Babbler meets HomoSapiens and Visionary ===\n";
433  Babbler bab;
434  VisitingTool& vista (bab);
435  homo1.apply (vista); // error handler (not Applicable to HomoSapiens)
436  homo2.apply (vista); // treats Visionary as Boss
437  }
438 
439  };
440 
441 
443  LAUNCHER (VisitingTool_concept, "unit common");
444 
445 
446 
447 }}} // namespace lumiera::visitor_concept_draft::test
Automatically use custom string conversion in C++ stream output.
any concrete visiting tool implementation has to inherit from this class for each kind of calls it wa...
Definition: run.hpp:40
virtual ReturnType apply(TOOL &)=0
to be defined by the DEFINE_PROCESSABLE_BY macro in all classes wanting to be treated by some tool ...
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition: util.hpp:514
static Tag< TOOL > tag
storage for the Tag registry for each concrete tool
Front-end for printf-style string template interpolation.
A front-end for using printf-style formatting.
Mixin for attaching a type tag to the concrete tool implementation.
Access point to singletons and other kinds of dependencies designated by type.
Definition: depend.hpp:280
static ReturnType callTrampoline(TAR &obj, TOOL &tool)
generator for Trampoline functions, used to dispatch calls down to the right "treat"-Function on the ...
Marker interface "visiting tool".
std::vector< Trampoline > table_
custom VTable for storing the Trampoline pointers
static lib::Depend< Dispatcher< TAR, TOOL > > instance
storage for the dispatcher table(s)
Simplistic test class runner.
Tool< RET > ToolBase
for templating the Tag and Dispatcher
For each possible call entry point via some subclass of the visitable hierarchy, we maintain a dispat...
Singleton services and Dependency Injection.
Lumiera public interface.
Definition: advice.cpp:104
Marker interface "visitable object".
static ReturnType dispatchOp(TAR &target, TOOL &tool)
#define DEFINE_PROCESSABLE_BY(TOOL)
mark a Visitable subclass as actually treatable by some "visiting tool".