1 ////////////////////////////////////////////////////////////////////////////////
2 // The Loki Library
3 // Copyright (c) 2001 by Andrei Alexandrescu
4 // This code accompanies the book:
5 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
6 // Patterns Applied". Copyright (c) 2001. Addison-Wesley.
7 // Permission to use, copy, modify, distribute and sell this software for any
8 // purpose is hereby granted without fee, provided that the above copyright
9 // notice appear in all copies and that both that copyright notice and this
10 // permission notice appear in supporting documentation.
11 // The author or Addison-Welsey Longman make no representations about the
12 // suitability of this software for any purpose. It is provided "as is"
13 // without express or implied warranty.
14 ////////////////////////////////////////////////////////////////////////////////
15
16 // Last update: June 20, 2001
17
18 #ifndef MULTIMETHODS_INC_
19 #define MULTIMETHODS_INC_
20
21 #include "Typelist.h"
22 #include "TypeInfo.h"
23 #include "Functor.h"
24 #include "AssocVector.h"
25
26 ////////////////////////////////////////////////////////////////////////////////
27 // IMPORTANT NOTE:
28 // The double dispatchers implemented below differ from the excerpts shown in
29 // the book - they are simpler while respecting the same interface.
30 ////////////////////////////////////////////////////////////////////////////////
31
32 namespace Loki
33 {
34 ////////////////////////////////////////////////////////////////////////////////
35 // class template InvocationTraits (helper)
36 // Helps implementing optional symmetry
37 ////////////////////////////////////////////////////////////////////////////////
38
39 namespace Private
40 {
41 template <class SomeLhs, class SomeRhs,
42 class Executor, typename ResultType>
43 struct InvocationTraits
44 {
45 static ResultType
46 DoDispatch(SomeLhs& lhs, SomeRhs& rhs,
47 Executor& exec, Int2Type<false>)
48 {
49 return exec.Fire(lhs, rhs);
50 }
51 static ResultType
52 DoDispatch(SomeLhs& lhs, SomeRhs& rhs,
53 Executor& exec, Int2Type<true>)
54 {
55 return exec.Fire(rhs, lhs);
56 }
57 };
58 }
59
60 ////////////////////////////////////////////////////////////////////////////////
61 // class template StaticDispatcher
62 // Implements an automatic static double dispatcher based on two typelists
63 ////////////////////////////////////////////////////////////////////////////////
64
65 template
66 <
67 class Executor,
68 class BaseLhs,
69 class TypesLhs,
70 bool symmetric = true,
71 class BaseRhs = BaseLhs,
72 class TypesRhs = TypesLhs,
73 typename ResultType = void
74 >
75 class StaticDispatcher
76 {
77 template <class SomeLhs>
78 static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
79 Executor exec, NullType)
80 { return exec.OnError(lhs, rhs); }
81
82 template <class TList, class SomeLhs>
83 static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
84 Executor exec, TList)
85 {
86 typedef typename TList::Head Head;
87 typedef typename TList::Tail Tail;
88
89 if (Head* p2 = dynamic_cast<Head*>(&rhs))
90 {
91 Int2Type<(symmetric &&
92 int(TL::IndexOf<TypesRhs, Head>::value) <
93 int(TL::IndexOf<TypesLhs, SomeLhs>::value))> i2t;
94
95 typedef Private::InvocationTraits<
96 SomeLhs, Head, Executor, ResultType> CallTraits;
97
98 return CallTraits::DoDispatch(lhs, *p2, exec, i2t);
99 }
100 return DispatchRhs(lhs, rhs, exec, Tail());
101 }
102
103 static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs,
104 Executor exec, NullType)
105 { return exec.OnError(lhs, rhs); }
106
107 template <class TList>
108 static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs,
109 Executor exec, TList)
110 {
111 typedef typename TList::Head Head;
112 typedef typename TList::Tail Tail;
113
114 if (Head* p1 = dynamic_cast<Head*>(&lhs))
115 {
116 return DispatchRhs(*p1, rhs, exec, TypesRhs());
117 }
118 return DispatchLhs(lhs, rhs, exec, Tail());
119 }
120
121 public:
122 static ResultType Go(BaseLhs& lhs, BaseRhs& rhs,
123 Executor exec)
124 { return DispatchLhs(lhs, rhs, exec, TypesLhs()); }
125 };
126
127 ////////////////////////////////////////////////////////////////////////////////
128 // class template BasicDispatcher
129 // Implements a logarithmic double dispatcher for functors (or functions)
130 // Doesn't offer automated casts or symmetry
131 ////////////////////////////////////////////////////////////////////////////////
132
133 template
134 <
135 class BaseLhs,
136 class BaseRhs = BaseLhs,
137 typename ResultType = void,
138 typename CallbackType = ResultType (*)(BaseLhs&, BaseRhs&)
139 >
140 class BasicDispatcher
141 {
142 typedef std::pair<TypeInfo,TypeInfo> KeyType;
143 typedef CallbackType MappedType;
144 typedef AssocVector<KeyType, MappedType> MapType;
145 MapType callbackMap_;
146
147 void DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun);
148 bool DoRemove(TypeInfo lhs, TypeInfo rhs);
149
150 public:
151 template <class SomeLhs, class SomeRhs>
152 void Add(CallbackType fun)
153 {
154 DoAdd(typeid(SomeLhs), typeid(SomeRhs), fun);
155 }
156
157 template <class SomeLhs, class SomeRhs>
158 bool Remove()
159 {
160 return DoRemove(typeid(SomeLhs), typeid(SomeRhs));
161 }
162
163 ResultType Go(BaseLhs& lhs, BaseRhs& rhs);
164 };
165
166 // Non-inline to reduce compile time overhead...
167 template <class BaseLhs, class BaseRhs,
168 typename ResultType, typename CallbackType>
169 void BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
170 ::DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun)
171 {
172 callbackMap_[KeyType(lhs, rhs)] = fun;
173 }
174
175 template <class BaseLhs, class BaseRhs,
176 typename ResultType, typename CallbackType>
177 bool BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
178 ::DoRemove(TypeInfo lhs, TypeInfo rhs)
179 {
180 return callbackMap_.erase(KeyType(lhs, rhs)) == 1;
181 }
182
183 template <class BaseLhs, class BaseRhs,
184 typename ResultType, typename CallbackType>
185 ResultType BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
186 ::Go(BaseLhs& lhs, BaseRhs& rhs)
187 {
188 typename MapType::key_type k(typeid(lhs),typeid(rhs));
189 typename MapType::iterator i = callbackMap_.find(k);
190 if (i == callbackMap_.end())
191 {
192 throw std::runtime_error("Function not found");
193 }
194 return (i->second)(lhs, rhs);
195 }
196
197 ////////////////////////////////////////////////////////////////////////////////
198 // class template StaticCaster
199 // Implementation of the CastingPolicy used by FunctorDispatcher
200 ////////////////////////////////////////////////////////////////////////////////
201
202 template <class To, class From>
203 struct StaticCaster
204 {
205 static To& Cast(From& obj)
206 {
207 return static_cast<To&>(obj);
208 }
209 };
210
211 ////////////////////////////////////////////////////////////////////////////////
212 // class template DynamicCaster
213 // Implementation of the CastingPolicy used by FunctorDispatcher
214 ////////////////////////////////////////////////////////////////////////////////
215
216 template <class To, class From>
217 struct DynamicCaster
218 {
219 static To& Cast(From& obj)
220 {
221 return dynamic_cast<To&>(obj);
222 }
223 };
224
225 ////////////////////////////////////////////////////////////////////////////////
226 // class template Private::FnDispatcherHelper
227 // Implements trampolines and argument swapping used by FnDispatcher
228 ////////////////////////////////////////////////////////////////////////////////
229
230 namespace Private
231 {
232 template <class BaseLhs, class BaseRhs,
233 class SomeLhs, class SomeRhs,
234 typename ResultType,
235 class CastLhs, class CastRhs,
236 ResultType (*Callback)(SomeLhs&, SomeRhs&)>
237 struct FnDispatcherHelper
238 {
239 static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs)
240 {
241 return Callback(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
242 }
243 static ResultType TrampolineR(BaseRhs& rhs, BaseLhs& lhs)
244 {
245 return Trampoline(lhs, rhs);
246 }
247 };
248 }
249
250 ////////////////////////////////////////////////////////////////////////////////
251 // class template FnDispatcher
252 // Implements an automatic logarithmic double dispatcher for functions
253 // Features automated conversions
254 ////////////////////////////////////////////////////////////////////////////////
255
256 template <class BaseLhs, class BaseRhs = BaseLhs,
257 typename ResultType = void,
258 template <class, class> class CastingPolicy = DynamicCaster,
259 template <class, class, class, class>
260 class DispatcherBackend = BasicDispatcher>
261 class FnDispatcher
262 {
263 DispatcherBackend<BaseLhs, BaseRhs, ResultType,
264 ResultType (*)(BaseLhs&, BaseRhs&)> backEnd_;
265
266 public:
267 template <class SomeLhs, class SomeRhs>
268 void Add(ResultType (*pFun)(BaseLhs&, BaseRhs&))
269 {
270 return backEnd_.Add<SomeLhs, SomeRhs>(pFun);
271 }
272
273 template <class SomeLhs, class SomeRhs,
274 ResultType (*callback)(SomeLhs&, SomeRhs&)>
275 void Add()
276 {
277 typedef Private::FnDispatcherHelper<
278 BaseLhs, BaseRhs,
279 SomeLhs, SomeRhs,
280 ResultType,
281 CastingPolicy<SomeLhs,BaseLhs>,
282 CastingPolicy<SomeRhs,BaseRhs>,
283 callback> Local;
284
285 Add<SomeLhs, SomeRhs>(&Local::Trampoline);
286 }
287
288 template <class SomeLhs, class SomeRhs,
289 ResultType (*callback)(SomeLhs&, SomeRhs&),
290 bool symmetric>
291 void Add()
292 {
293 typedef Private::FnDispatcherHelper<
294 BaseLhs, BaseRhs,
295 SomeLhs, SomeRhs,
296 ResultType,
297 CastingPolicy<SomeLhs,BaseLhs>,
298 CastingPolicy<SomeRhs,BaseRhs>,
299 callback> Local;
300
301 Add<SomeLhs, SomeRhs>(&Local::Trampoline);
302 if (symmetric)
303 {
304 Add<SomeRhs, SomeLhs>(&Local::TrampolineR);
305 }
306 }
307
308 template <class SomeLhs, class SomeRhs>
309 void Remove()
310 {
311 backEnd_.Remove<SomeLhs, SomeRhs>();
312 }
313
314 ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
315 {
316 return backEnd_.Go(lhs, rhs);
317 }
318 };
319
320 ////////////////////////////////////////////////////////////////////////////////
321 // class template FunctorDispatcherAdaptor
322 // permits use of FunctorDispatcher under gcc.2.95.2/3
323 ///////////////////////////////////////////////////////////////////////////////
324
325 namespace Private
326 {
327 template <class BaseLhs, class BaseRhs,
328 class SomeLhs, class SomeRhs,
329 typename ResultType,
330 class CastLhs, class CastRhs,
331 class Fun, bool SwapArgs>
332 class FunctorDispatcherHelper
333 {
334 Fun fun_;
335 ResultType Fire(BaseLhs& lhs, BaseRhs& rhs,Int2Type<false>)
336 {
337 return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
338 }
339 ResultType Fire(BaseLhs& rhs, BaseRhs& lhs,Int2Type<true>)
340 {
341 return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
342 }
343 public:
344 FunctorDispatcherHelper(const Fun& fun) : fun_(fun) {}
345
346 ResultType operator()(BaseLhs& lhs, BaseRhs& rhs)
347 {
348 return Fire(lhs,rhs,Int2Type<SwapArgs>());
349 }
350 };
351 }
352
353 ////////////////////////////////////////////////////////////////////////////////
354 // class template FunctorDispatcher
355 // Implements a logarithmic double dispatcher for functors
356 // Features automated casting
357 ////////////////////////////////////////////////////////////////////////////////
358
359 template <class BaseLhs, class BaseRhs = BaseLhs,
360 typename ResultType = void,
361 template <class, class> class CastingPolicy = DynamicCaster,
362 template <class, class, class, class>
363 class DispatcherBackend = BasicDispatcher>
364 class FunctorDispatcher
365 {
366 typedef TYPELIST_2(BaseLhs&, BaseRhs&) ArgsList;
367 typedef Functor<ResultType, ArgsList, DEFAULT_THREADING> FunctorType;
368
369 DispatcherBackend<BaseLhs, BaseRhs, ResultType, FunctorType> backEnd_;
370
371 public:
372 template <class SomeLhs, class SomeRhs, class Fun>
373 void Add(const Fun& fun)
374 {
375 typedef Private::FunctorDispatcherHelper<
376 BaseLhs, BaseRhs,
377 SomeLhs, SomeRhs,
378 ResultType,
379 CastingPolicy<SomeLhs, BaseLhs>,
380 CastingPolicy<SomeRhs, BaseRhs>,
381 Fun, false> Adapter;
382
383 backEnd_.Add<SomeLhs, SomeRhs>(FunctorType(Adapter(fun)));
384 }
385 template <class SomeLhs, class SomeRhs, bool symmetric, class Fun>
386 void Add(const Fun& fun)
387 {
388 Add<SomeLhs,SomeRhs>(fun);
389
390 if (symmetric)
391 {
392 // Note: symmetry only makes sense where BaseLhs==BaseRhs
393 typedef Private::FunctorDispatcherHelper<
394 BaseLhs, BaseLhs,
395 SomeLhs, SomeRhs,
396 ResultType,
397 CastingPolicy<SomeLhs, BaseLhs>,
398 CastingPolicy<SomeRhs, BaseLhs>,
399 Fun, true> AdapterR;
400
401 backEnd_.Add<SomeRhs, SomeLhs>(FunctorType(AdapterR(fun)));
402 }
403 }
404
405 template <class SomeLhs, class SomeRhs>
406 void Remove()
407 {
408 backEnd_.Remove<SomeLhs, SomeRhs>();
409 }
410
411 ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
412 {
413 return backEnd_.Go(lhs, rhs);
414 }
415 };
416 } // namespace Loki
417
418 ////////////////////////////////////////////////////////////////////////////////
419 // Change log:
420 // June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
421 ////////////////////////////////////////////////////////////////////////////////
422
423 #endif