]> git.cworth.org Git - vogl/blob - src/extlib/loki/include/loki/MultiMethods.h
Initial vogl checkin
[vogl] / src / extlib / loki / include / loki / MultiMethods.h
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-Wesley 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 #ifndef LOKI_MULTIMETHODS_INC_
16 #define LOKI_MULTIMETHODS_INC_
17
18 // $Id: MultiMethods.h 751 2006-10-17 19:50:37Z syntheticpp $
19
20
21 #include "Typelist.h"
22 #include "LokiTypeInfo.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         {
81                 return exec.OnError(lhs, rhs);
82         }
83
84         template <class Head, class Tail, class SomeLhs>
85         static ResultType DispatchRhs(SomeLhs &lhs, BaseRhs &rhs,
86                                       Executor exec, Typelist<Head, Tail>)
87         {
88                 if (Head *p2 = dynamic_cast<Head *>(&rhs))
89                 {
90                         Int2Type<(symmetric &&
91                                   int(TL::IndexOf<TypesRhs, Head>::value) <
92                                   int(TL::IndexOf<TypesLhs, SomeLhs>::value))> i2t;
93
94                         typedef Private::InvocationTraits<
95                         SomeLhs, Head, Executor, ResultType> CallTraits;
96
97                         return CallTraits::DoDispatch(lhs, *p2, exec, i2t);
98                 }
99                 return DispatchRhs(lhs, rhs, exec, Tail());
100         }
101
102         static ResultType DispatchLhs(BaseLhs &lhs, BaseRhs &rhs,
103                                       Executor exec, NullType)
104         {
105                 return exec.OnError(lhs, rhs);
106         }
107
108         template <class Head, class Tail>
109         static ResultType DispatchLhs(BaseLhs &lhs, BaseRhs &rhs,
110                                       Executor exec, Typelist<Head, Tail>)
111         {
112                 if (Head *p1 = dynamic_cast<Head *>(&lhs))
113                 {
114                         return DispatchRhs(*p1, rhs, exec, TypesRhs());
115                 }
116                 return DispatchLhs(lhs, rhs, exec, Tail());
117         }
118
119 public:
120         static ResultType Go(BaseLhs &lhs, BaseRhs &rhs,
121                              Executor exec)
122         {
123                 return DispatchLhs(lhs, rhs, exec, TypesLhs());
124         }
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_.template 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(bool = true) // [gcc] dummy bool
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_.template 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 LOKI_TYPELIST_2(BaseLhs &, BaseRhs &) ArgsList;
367         typedef Functor<ResultType, ArgsList, LOKI_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_.template 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_.template Add<SomeRhs, SomeLhs>(FunctorType(AdapterR(fun)));
402                 }
403         }
404
405         template <class SomeLhs, class SomeRhs>
406         void Remove()
407         {
408                 backEnd_.template 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
420 #endif // end file guardian
421