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-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
posted @ 2012-10-31 15:16  crazylhf  阅读(161)  评论(0)    收藏  举报