MultiMethods.h

00001 
00002 // The Loki Library
00003 // Copyright (c) 2001 by Andrei Alexandrescu
00004 // This code accompanies the book:
00005 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design 
00006 //     Patterns Applied". Copyright (c) 2001. Addison-Wesley.
00007 // Permission to use, copy, modify, distribute and sell this software for any 
00008 //     purpose is hereby granted without fee, provided that the above copyright 
00009 //     notice appear in all copies and that both that copyright notice and this 
00010 //     permission notice appear in supporting documentation.
00011 // The author or Addison-Wesley Longman make no representations about the 
00012 //     suitability of this software for any purpose. It is provided "as is" 
00013 //     without express or implied warranty.
00015 #ifndef LOKI_MULTIMETHODS_INC_
00016 #define LOKI_MULTIMETHODS_INC_
00017 
00018 // $Id: MultiMethods.h 751 2006-10-17 19:50:37Z syntheticpp $
00019 
00020 
00021 #include "Typelist.h"
00022 #include "LokiTypeInfo.h"
00023 #include "Functor.h"
00024 #include "AssocVector.h"
00025 
00027 // IMPORTANT NOTE:
00028 // The double dispatchers implemented below differ from the excerpts shown in
00029 // the book - they are simpler while respecting the same interface.
00031 
00032 namespace Loki
00033 {
00035 // class template InvocationTraits (helper)
00036 // Helps implementing optional symmetry
00038 
00039     namespace Private
00040     {
00041         template <class SomeLhs, class SomeRhs, 
00042             class Executor, typename ResultType>
00043         struct InvocationTraits
00044         {
00045             static ResultType 
00046         DoDispatch(SomeLhs& lhs, SomeRhs& rhs, 
00047             Executor& exec, Int2Type<false>)
00048             {
00049                 return exec.Fire(lhs, rhs);
00050             }
00051             static ResultType 
00052         DoDispatch(SomeLhs& lhs, SomeRhs& rhs, 
00053             Executor& exec, Int2Type<true>)
00054             {
00055                 return exec.Fire(rhs, lhs);
00056             }
00057         };
00058     }
00059 
00061 // class template StaticDispatcher
00062 // Implements an automatic static double dispatcher based on two typelists
00064 
00065     template
00066     <
00067         class Executor,
00068         class BaseLhs, 
00069         class TypesLhs,
00070         bool symmetric = true,
00071         class BaseRhs = BaseLhs,
00072         class TypesRhs = TypesLhs,
00073         typename ResultType = void
00074     >
00075     class StaticDispatcher
00076     {
00077         template <class SomeLhs>
00078         static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
00079             Executor exec, NullType)
00080         { return exec.OnError(lhs, rhs); }
00081         
00082         template <class Head, class Tail, class SomeLhs>
00083         static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
00084             Executor exec, Typelist<Head, Tail>)
00085         {            
00086             if (Head* p2 = dynamic_cast<Head*>(&rhs))
00087             {
00088                 Int2Type<(symmetric &&
00089                           int(TL::IndexOf<TypesRhs, Head>::value) <
00090                           int(TL::IndexOf<TypesLhs, SomeLhs>::value))> i2t;
00091 
00092                 typedef Private::InvocationTraits< 
00093                         SomeLhs, Head, Executor, ResultType> CallTraits;
00094                     
00095                 return CallTraits::DoDispatch(lhs, *p2, exec, i2t);
00096             }
00097             return DispatchRhs(lhs, rhs, exec, Tail());
00098         }
00099         
00100         static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs,
00101             Executor exec, NullType)
00102         { return exec.OnError(lhs, rhs); }
00103         
00104         template <class Head, class Tail>
00105         static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs,
00106             Executor exec, Typelist<Head, Tail>)
00107         {            
00108             if (Head* p1 = dynamic_cast<Head*>(&lhs))
00109             {
00110                 return DispatchRhs(*p1, rhs, exec, TypesRhs());
00111             }
00112             return DispatchLhs(lhs, rhs, exec, Tail());
00113         }
00114 
00115     public:
00116         static ResultType Go(BaseLhs& lhs, BaseRhs& rhs,
00117             Executor exec)
00118         { return DispatchLhs(lhs, rhs, exec, TypesLhs()); }
00119     };
00120     
00122 // class template BasicDispatcher
00123 // Implements a logarithmic double dispatcher for functors (or functions)
00124 // Doesn't offer automated casts or symmetry
00126 
00127     template
00128     <
00129         class BaseLhs,
00130         class BaseRhs = BaseLhs,
00131         typename ResultType = void,
00132         typename CallbackType = ResultType (*)(BaseLhs&, BaseRhs&)
00133     >
00134     class BasicDispatcher
00135     {
00136         typedef std::pair<TypeInfo,TypeInfo> KeyType;
00137         typedef CallbackType MappedType;
00138         typedef AssocVector<KeyType, MappedType> MapType;
00139         MapType callbackMap_;
00140         
00141         void DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun);
00142         bool DoRemove(TypeInfo lhs, TypeInfo rhs);
00143         
00144     public:
00145         template <class SomeLhs, class SomeRhs>
00146         void Add(CallbackType fun)
00147         {
00148             DoAdd(typeid(SomeLhs), typeid(SomeRhs), fun);
00149         }
00150         
00151         template <class SomeLhs, class SomeRhs>
00152         bool Remove()
00153         {
00154             return DoRemove(typeid(SomeLhs), typeid(SomeRhs));
00155         }
00156         
00157         ResultType Go(BaseLhs& lhs, BaseRhs& rhs);
00158     };
00159 
00160     // Non-inline to reduce compile time overhead...
00161     template <class BaseLhs, class BaseRhs, 
00162         typename ResultType, typename CallbackType>
00163     void BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
00164          ::DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun)
00165     {
00166         callbackMap_[KeyType(lhs, rhs)] = fun;
00167     }
00168         
00169     template <class BaseLhs, class BaseRhs, 
00170         typename ResultType, typename CallbackType>
00171     bool BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
00172          ::DoRemove(TypeInfo lhs, TypeInfo rhs)
00173     {
00174         return callbackMap_.erase(KeyType(lhs, rhs)) == 1;
00175     }
00176 
00177     template <class BaseLhs, class BaseRhs, 
00178         typename ResultType, typename CallbackType>
00179     ResultType BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
00180                ::Go(BaseLhs& lhs, BaseRhs& rhs)
00181     {
00182         typename MapType::key_type k(typeid(lhs),typeid(rhs));
00183         typename MapType::iterator i = callbackMap_.find(k);
00184         if (i == callbackMap_.end())
00185         {
00186                 throw std::runtime_error("Function not found");
00187         }
00188         return (i->second)(lhs, rhs);
00189     }
00190 
00192 // class template StaticCaster
00193 // Implementation of the CastingPolicy used by FunctorDispatcher
00195 
00196     template <class To, class From>
00197     struct StaticCaster
00198     {
00199         static To& Cast(From& obj)
00200         {
00201             return static_cast<To&>(obj);
00202         }
00203     };
00204 
00206 // class template DynamicCaster
00207 // Implementation of the CastingPolicy used by FunctorDispatcher
00209 
00210     template <class To, class From>
00211     struct DynamicCaster
00212     {
00213         static To& Cast(From& obj)
00214         {
00215             return dynamic_cast<To&>(obj);
00216         }
00217     };
00218 
00220 // class template Private::FnDispatcherHelper
00221 // Implements trampolines and argument swapping used by FnDispatcher
00223 
00224     namespace Private
00225     {
00226         template <class BaseLhs, class BaseRhs,
00227         class SomeLhs, class SomeRhs,
00228             typename ResultType,
00229             class CastLhs, class CastRhs,
00230             ResultType (*Callback)(SomeLhs&, SomeRhs&)>
00231         struct FnDispatcherHelper
00232         {
00233             static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs)
00234             {
00235                 return Callback(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
00236             }
00237             static ResultType TrampolineR(BaseRhs& rhs, BaseLhs& lhs)
00238             {
00239                 return Trampoline(lhs, rhs);
00240             }
00241         };
00242     }
00243 
00245 // class template FnDispatcher
00246 // Implements an automatic logarithmic double dispatcher for functions
00247 // Features automated conversions
00249 
00250     template <class BaseLhs, class BaseRhs = BaseLhs,
00251               typename ResultType = void,
00252               template <class, class> class CastingPolicy = DynamicCaster,
00253               template <class, class, class, class>
00254               class DispatcherBackend = BasicDispatcher>
00255     class FnDispatcher
00256     {
00257         DispatcherBackend<BaseLhs, BaseRhs, ResultType, 
00258             ResultType (*)(BaseLhs&, BaseRhs&)> backEnd_;
00259         
00260     public:
00261         template <class SomeLhs, class SomeRhs>
00262         void Add(ResultType (*pFun)(BaseLhs&, BaseRhs&))
00263         {
00264             return backEnd_.template Add<SomeLhs, SomeRhs>(pFun);
00265         }        
00266         
00267         template <class SomeLhs, class SomeRhs,
00268             ResultType (*callback)(SomeLhs&, SomeRhs&)>
00269         void Add()
00270         {
00271         typedef Private::FnDispatcherHelper<
00272                     BaseLhs, BaseRhs, 
00273                     SomeLhs, SomeRhs,
00274                     ResultType,
00275                     CastingPolicy<SomeLhs,BaseLhs>, 
00276                     CastingPolicy<SomeRhs,BaseRhs>, 
00277                     callback> Local;
00278 
00279             Add<SomeLhs, SomeRhs>(&Local::Trampoline);
00280         }
00281         
00282         template <class SomeLhs, class SomeRhs,
00283             ResultType (*callback)(SomeLhs&, SomeRhs&),
00284             bool symmetric>
00285         void Add(bool = true) // [gcc] dummy bool
00286         {
00287         typedef Private::FnDispatcherHelper<
00288                     BaseLhs, BaseRhs, 
00289                     SomeLhs, SomeRhs,
00290                     ResultType,
00291                     CastingPolicy<SomeLhs,BaseLhs>, 
00292                     CastingPolicy<SomeRhs,BaseRhs>, 
00293                     callback> Local;
00294 
00295             Add<SomeLhs, SomeRhs>(&Local::Trampoline);
00296             if (symmetric)
00297             {
00298                 Add<SomeRhs, SomeLhs>(&Local::TrampolineR);
00299             }
00300         }
00301         
00302         template <class SomeLhs, class SomeRhs>
00303         void Remove()
00304         {
00305             backEnd_.template Remove<SomeLhs, SomeRhs>();
00306         }
00307 
00308         ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
00309         {
00310             return backEnd_.Go(lhs, rhs);
00311         }
00312     };
00313 
00315 // class template FunctorDispatcherAdaptor
00316 // permits use of FunctorDispatcher under gcc.2.95.2/3
00318 
00319     namespace Private
00320     {
00321     template <class BaseLhs, class BaseRhs,
00322           class SomeLhs, class SomeRhs,
00323           typename ResultType,
00324           class CastLhs, class CastRhs,
00325           class Fun, bool SwapArgs>
00326         class FunctorDispatcherHelper 
00327         {
00328             Fun fun_;
00329             ResultType Fire(BaseLhs& lhs, BaseRhs& rhs,Int2Type<false>)
00330             {
00331                 return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
00332             }
00333             ResultType Fire(BaseLhs& rhs, BaseRhs& lhs,Int2Type<true>)
00334             {
00335                 return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
00336             }
00337         public:
00338             FunctorDispatcherHelper(const Fun& fun) : fun_(fun) {}
00339 
00340             ResultType operator()(BaseLhs& lhs, BaseRhs& rhs)
00341             {
00342                 return Fire(lhs,rhs,Int2Type<SwapArgs>());
00343             }
00344         };
00345     }
00346 
00348 // class template FunctorDispatcher
00349 // Implements a logarithmic double dispatcher for functors
00350 // Features automated casting
00352 
00353     template <class BaseLhs, class BaseRhs = BaseLhs,
00354               typename ResultType = void,
00355               template <class, class> class CastingPolicy = DynamicCaster, 
00356               template <class, class, class, class>
00357               class DispatcherBackend = BasicDispatcher>
00358     class FunctorDispatcher
00359     {
00360         typedef LOKI_TYPELIST_2(BaseLhs&, BaseRhs&) ArgsList;
00361         typedef Functor<ResultType, ArgsList, LOKI_DEFAULT_THREADING> FunctorType;
00362 
00363         DispatcherBackend<BaseLhs, BaseRhs, ResultType, FunctorType> backEnd_;
00364 
00365     public:
00366         template <class SomeLhs, class SomeRhs, class Fun>
00367         void Add(const Fun& fun)
00368         {
00369             typedef Private::FunctorDispatcherHelper<
00370                     BaseLhs, BaseRhs,
00371                     SomeLhs, SomeRhs,
00372                     ResultType,
00373                     CastingPolicy<SomeLhs, BaseLhs>,
00374                     CastingPolicy<SomeRhs, BaseRhs>,
00375                     Fun, false> Adapter;
00376 
00377             backEnd_.template Add<SomeLhs, SomeRhs>(FunctorType(Adapter(fun)));
00378     }
00379         template <class SomeLhs, class SomeRhs, bool symmetric, class Fun>
00380         void Add(const Fun& fun)
00381         {
00382         Add<SomeLhs,SomeRhs>(fun);
00383 
00384         if (symmetric)
00385         {
00386         // Note: symmetry only makes sense where BaseLhs==BaseRhs
00387                 typedef Private::FunctorDispatcherHelper<
00388                     BaseLhs, BaseLhs,
00389                     SomeLhs, SomeRhs,
00390                     ResultType,
00391                     CastingPolicy<SomeLhs, BaseLhs>,
00392                     CastingPolicy<SomeRhs, BaseLhs>,
00393                     Fun, true> AdapterR;
00394 
00395                 backEnd_.template Add<SomeRhs, SomeLhs>(FunctorType(AdapterR(fun)));
00396         }
00397         }
00398         
00399         template <class SomeLhs, class SomeRhs>
00400         void Remove()
00401         {
00402             backEnd_.template Remove<SomeLhs, SomeRhs>();
00403         }
00404 
00405         ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
00406         {
00407             return backEnd_.Go(lhs, rhs);
00408         }
00409     };
00410 } // namespace Loki
00411 
00412 
00413 
00414 #endif // end file guardian
00415 

Generated on Sun Feb 25 16:52:26 2007 for Loki by  doxygen 1.5.1-p1