Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
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
46#include "lib/test/run.hpp"
47#include "lib/format-cout.hpp"
48#include "lib/format-string.hpp"
49#include "lib/depend.hpp"
50
51#include <vector>
52
53using util::_Fmt;
54using std::string;
55
56
57namespace lumiera {
58 namespace visitor_concept_draft {
59
60 // ================================================================== Library ====
61
62
63
64 template<class TOOL> class Tag;
65
66
67 template<class TOOL, class TOOLImpl>
69 {
70 static Tag<TOOL> tag;
71 };
72
73
74 template<class TOOL>
75 class Tag
76 {
77 size_t tagID;
78 static size_t lastRegisteredID;
79
80 public:
81 Tag() : tagID(0) { }
82 operator size_t() const { return tagID; }
83
84
85 template<class TOOLImpl>
86 static Tag&
87 get (TOOLImpl* const =0) // param used to pass type info
88 {
89 // we have a race condition here...
91 if (!t)
93 return t;
94 }
95
96 };
97
98
99
101 template<class TOOL, class TOOLImpl>
103
104 template<class TOOL>
106
107
108
109
110
111
113 template<typename RET>
114 class Tool
115 {
116 public:
117 using ReturnType = RET;
119
120 virtual ~Tool() { };
121
124 virtual Tag<ToolBase> getTag() =0;
125 };
126
127
129 template<class TOOLImpl, class BASE =Tool<void>>
131 : public BASE
132 {
133 using ToolBase = BASE::ToolBase;
134
135 public:
136 virtual Tag<ToolBase>
138 {
139 TOOLImpl* typeKey = 0;
140 return Tag<ToolBase>::get (typeKey);
141 }
142 };
143
144
145
146
152 template<class TAR, class TOOL>
154 {
155 using ReturnType = TOOL::ReturnType;
156
162 template<class TOOLImpl>
163 static ReturnType
164 callTrampoline (TAR& obj, TOOL& tool)
165 {
166 // cast down to real implementation type
167 CHECK (INSTANCEOF (TOOLImpl, &tool));
168 TOOLImpl& toolObj = static_cast<TOOLImpl&> (tool);
169
170 // trigger (compile time) overload resolution
171 // based on concrete type, then dispatch the call.
172 // Note this may cause obj to be upcasted.
173 return toolObj.treat (obj);
174 }
175
176 typedef ReturnType (*Trampoline) (TAR&, TOOL& );
177
178
180 std::vector<Trampoline> table_;
181
182
183 inline bool
184 is_known (size_t id)
185 {
186 return id<=table_.size() and table_[id-1];
187 }
188
189 inline void
190 storePtr (size_t id, Trampoline func)
191 {
192 // lacks error- and concurrency handling....
193 if (id>table_.size())
194 table_.resize (id);
195 table_[id-1] = func;
196 }
197
198 inline Trampoline
200 {
201 if (id<=table_.size() and table_[id-1])
202 return table_[id-1];
203 else
204 return &errorHandler;
205 }
206
207 static ReturnType
208 errorHandler (TAR&, TOOL&)
209 {
210 cout << "Error Handler: unregistered combination of (Tool, TargetObject) invoked!\n";
211 }
212
213
214 public:
216
217 inline ReturnType
218 forwardCall (TAR& target, TOOL& tool)
219 {
220 // get concrete type via tool's VTable
221 Tag<TOOL> index = tool.getTag();
222 return (*storedTrampoline(index)) (target, tool);
223 }
224
225 template<class TOOLImpl>
226 inline void
227 enrol (TOOLImpl* typeKey)
228 {
229 Tag<TOOL>& index = Tag<TOOL>::get (typeKey);
230 if (is_known (index))
231 return;
232 else
233 {
234 Trampoline func = &callTrampoline<TOOLImpl>;
235 storePtr (index, func);
236 }
237
238 }
239 };
240
242 template<class TAR, class TOOL>
244
245
246
247
248
254 template<class TAR, class TOOLImpl, class BASE=Tool<void> >
256 {
257 using Ret = BASE::ReturnType;
258 using ToolBase = BASE::ToolBase;
259
260 protected:
262 {
263 TOOLImpl* typeKey = 0;
264 Dispatcher<TAR,ToolBase>::instance().enrol (typeKey);
265 }
266
267 virtual ~Applicable () {}
268
269 public:
270 // we could enforce the definition of treat()-functions by:
271 //
272 // virtual Ret treat (TAR& target) = 0;
273
274 };
275
276
277
278
279
282 template
283 < class TOOL = Tool<void>
284 >
286 {
287 protected:
288 virtual ~Visitable() { };
289
291 using ToolBase = TOOL::ToolBase;
292 using ReturnType = TOOL::ReturnType;
293
299 template <class TAR>
300 static inline ReturnType
301 dispatchOp (TAR& target, TOOL& tool)
302 {
303 return Dispatcher<TAR,ToolBase>::instance().forwardCall (target,tool);
304 }
305
306 public:
309 virtual ReturnType apply (TOOL&) = 0;
310 };
311
312
317#define DEFINE_PROCESSABLE_BY(TOOL) \
318 virtual ReturnType apply (TOOL& tool) \
319 { return dispatchOp (*this, tool); }
320
321
322 // =============================================================(End) Library ====
323
324
325
326
327
328 namespace test {
329
331
332 class HomoSapiens : public Visitable<>
333 {
334 public:
336 };
337
338 class Boss : public HomoSapiens
339 {
340 public:
342 };
343
344 class BigBoss : public Boss
345 {
346 public:
348 };
349
350 class Leader : public Boss
351 {
352 };
353
354 class Visionary : public Leader
355 {
356 };
357
358
360 : public VisitingTool
361 {
362 protected:
363 void talk_to (string guy)
364 {
365 cout << _Fmt{"Hello %s, nice to meet you...\n"} % guy;
366 }
367 };
368
369
371 : public Applicable<Boss,Babbler>,
372 public Applicable<BigBoss,Babbler>,
373 public Applicable<Visionary,Babbler>,
374 public ToolType<Babbler, VerboseVisitor>
375 {
376 public:
377 void treat (Boss&) { talk_to("Boss"); }
378 void treat (BigBoss&) { talk_to("Big Boss"); }
379
380 };
381
382
383
384
385
386
387
388 /*********************************************************************/
399 class VisitingTool_concept : public Test
400 {
401 virtual void run(Arg)
402 {
405 }
406
408 {
409 Boss x1;
410 BigBoss x2;
411
412 // masquerade as HomoSapiens...
413 HomoSapiens& homo1 (x1);
414 HomoSapiens& homo2 (x2);
415
416 cout << "=== Babbler meets Boss and BigBoss ===\n";
417 Babbler bab;
418 VisitingTool& vista (bab);
419 homo1.apply (vista);
420 homo2.apply (vista);
421 }
422
424 {
425 HomoSapiens x1;
426 Visionary x2;
427
428 HomoSapiens& homo1 (x1);
429 HomoSapiens& homo2 (x2);
430
431 cout << "=== Babbler meets HomoSapiens and Visionary ===\n";
432 Babbler bab;
433 VisitingTool& vista (bab);
434 homo1.apply (vista); // error handler (not Applicable to HomoSapiens)
435 homo2.apply (vista); // treats Visionary as Boss
436 }
437
438 };
439
440
443
444
445
446}}} // namespace lumiera::visitor_concept_draft::test
Access point to singletons and other kinds of dependencies designated by type.
Definition depend.hpp:281
any concrete visiting tool implementation has to inherit from this class for each kind of calls it wa...
For each possible call entry point via some subclass of the visitable hierarchy, we maintain a dispat...
ReturnType forwardCall(TAR &target, TOOL &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)
static ReturnType errorHandler(TAR &, TOOL &)
static ReturnType callTrampoline(TAR &obj, TOOL &tool)
generator for Trampoline functions, used to dispatch calls down to the right "treat"-Function on the ...
static Tag & get(TOOLImpl *const =0)
Mixin for attaching a type tag to the concrete tool implementation.
virtual Tag< ToolBase > getTag()
use RTTI for all visiting tools
Marker interface "visiting tool".
virtual Tag< ToolBase > getTag()=0
use RTTI for all visiting tools
Tool< RET > ToolBase
for templating the Tag and Dispatcher
Marker interface "visitable object".
static ReturnType dispatchOp(TAR &target, TOOL &tool)
virtual ReturnType apply(TOOL &)=0
to be defined by the DEFINE_PROCESSABLE_BY macro in all classes wanting to be treated by some tool
A front-end for using printf-style formatting.
Singleton services and Dependency Injection.
Automatically use custom string conversion in C++ stream output.
Front-end for printf-style string template interpolation.
Lumiera public interface.
Definition advice.hpp:102
Test runner and basic definitions for tests.
Simplistic test class runner.
#define LAUNCHER(_TEST_CLASS_, _GROUPS_)
Definition run.hpp:116
static Tag< TOOL > tag
storage for the Tag registry for each concrete tool
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition util.hpp:514