Lumiera  0.pre.03
»edit your freedom«
visitor-dispatcher.hpp
Go to the documentation of this file.
1 /*
2  VISITOR-DISPATCHER.hpp - visitor implementation details
3 
4  Copyright (C) Lumiera.org
5  2008, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 
31 #ifndef LUMIERA_VISITOR_DISPATCHER_H
32 #define LUMIERA_VISITOR_DISPATCHER_H
33 
34 #include "lib/error.hpp"
35 #include "lib/util.hpp"
36 #include "lib/sync-classlock.hpp"
37 #include "lib/depend.hpp"
38 #include "lib/util.hpp"
39 
40 #include <vector>
41 
42 
43 namespace lib {
44 namespace visitor {
45 
46  using lib::ClassLock;
47  using lib::Depend;
48 
49 
50  template<class TOOL> class Tag;
51 
52 
53  template<class TOOL, class TOOLImpl>
55  {
56  static Tag<TOOL> tag;
57  };
58 
64  template<class TOOL>
65  class Tag
66  {
67  size_t tagID;
68  static size_t lastRegisteredID;
69 
70  static void
71  generateID (size_t& id)
72  {
73  ClassLock<Tag> guard;
74  if (!id)
75  id = ++lastRegisteredID;
76  }
77 
78  public:
79  Tag() : tagID(0) { }
80  operator size_t() const { return tagID; }
81 
82 
83  template<class TOOLImpl>
84  static Tag&
85  get (TOOLImpl* const =0)
86  {
88  if (!t) generateID (t.tagID);
89  return t;
90  }
91 
92  };
93 
94 
95 
97  template<class TOOL, class TOOLImpl>
99 
100  template<class TOOL>
101  size_t Tag<TOOL>::lastRegisteredID (0);
102 
103 
104 
105 
106 
107 
108 
109 
117  template<class TAR, class TOOL>
119  {
120  typedef typename TOOL::ReturnType ReturnType;
121 
127  template<class TOOLImpl>
128  static ReturnType
129  callTrampoline (TAR& obj, TOOL& tool)
130  {
131  // cast down to real implementation type
132  REQUIRE (INSTANCEOF (TOOLImpl, &tool));
133  TOOLImpl& toolObj = static_cast<TOOLImpl&> (tool);
134 
135  // trigger (compile time) overload resolution
136  // based on concrete type, then dispatch the call.
137  // Note this may cause obj to be upcasted.
138  return toolObj.treat (obj);
139  }
140 
141  typedef ReturnType (*Trampoline) (TAR&, TOOL& );
142 
143 
145  std::vector<Trampoline> table_;
146 
147 
148  void
149  accomodate (size_t index)
150  {
151  ClassLock<Dispatcher> guard; // note: this lock is also used for the singleton!
152  if (index > table_.size())
153  table_.resize (index); // performance bottleneck?? TODO: measure the real impact!
154  }
155 
156  inline bool
157  is_known (size_t id)
158  {
159  return id<=table_.size() && table_[id-1];
160  }
161 
162  inline void
163  storePtr (size_t id, Trampoline func)
164  {
165  REQUIRE (func);
166  REQUIRE (0 < id);
167  if (id>table_.size())
168  accomodate (id);
169  table_[id-1] = func;
170  }
171 
172  inline Trampoline
173  storedTrampoline (size_t id)
174  {
175  if (id<=table_.size() && table_[id-1])
176  return table_[id-1];
177  else
178  return &errorHandler;
179  }
180 
181  static ReturnType
182  errorHandler (TAR& target, TOOL& tool)
183  {
184  return tool.onUnknown (target);
185  }
186 
187 
188  public:
190 
191  inline ReturnType
192  forwardCall (TAR& target, TOOL& tool)
193  {
194  // get concrete type via tool's VTable
195  Tag<TOOL> index = tool.getTag();
196  return (*storedTrampoline(index)) (target, tool);
197  }
198 
199  template<class TOOLImpl>
200  inline void
201  enrol(TOOLImpl* typeref)
202  {
203  Tag<TOOL>& index = Tag<TOOL>::get (typeref);
204  if (is_known (index))
205  return;
206  else
207  {
208  Trampoline func = &callTrampoline<TOOLImpl>;
209  storePtr (index, func);
210  }
211 
212  }
213  };
214 
216  template<class TAR, class TOOL>
218 
219 
220 
221 
222 }} // namespace lib::visitor
223 #endif
size_t tagID
tag value
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition: util.hpp:492
Access point to singletons and other kinds of dependencies designated by type.
Definition: depend.hpp:289
Implementation namespace for support and library code.
static Tag< TOOL > tag
storage for the Tag registry for each concrete tool
static ReturnType callTrampoline(TAR &obj, TOOL &tool)
generator for Trampoline functions, used to dispatch calls down to the right "treat"-Function on the ...
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
A special implementation of lib::Sync, where the storage of the object monitor is associated directly...
Singleton services and Dependency Injection.
Lumiera error handling (C++ interface).
Type tag for concrete visiting tool classes.
A synchronisation protection guard employing a lock scoped to the parameter type as a whole...
For each possible call entry point via some subclass of the visitable hierarchy, we maintain a dispat...
static Depend< Dispatcher< TAR, TOOL > > instance
storage for the dispatcher table(s)
std::vector< Trampoline > table_
VTable for storing the Trampoline pointers.