//////////////////////////////////////////////////////////////////////////////// // The Loki Library // Copyright (c) 2001 by Andrei Alexandrescu // This code accompanies the book: // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design // Patterns Applied". Copyright (c) 2001. Addison-Wesley. // Permission to use, copy, modify, distribute and sell this software for any // purpose is hereby granted without fee, provided that the above copyright // notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. // The author or Addison-Welsey Longman make no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// // Last update: Feb 19, 2003 // All dispatchers now support void as return type. // // // The port now uses Tye2Type-parameters instead of plain pointers as // a workaround of VC's explicit template argument specification bug. // // For example: // The original declaration of BasicDispatcher::Add looks like this: // // template // void Add(CallbackType fun); // // and you call it like this: // obj.Add(yourFun); // // This port uses: // // template // void Add(CallbackType fun, Type2Type, Type2Type); // // and you call it like this: // obj.Add(yourFun, Type2Type(), Type2Type()); #ifndef MULTIMETHODS_INC_ #define MULTIMETHODS_INC_ #include "Typelist.h" #include "TypeInfo.h" #include "Functor.h" #include "AssocVector.h" //////////////////////////////////////////////////////////////////////////////// // IMPORTANT NOTE: // The double dispatchers implemented below differ from the excerpts shown in // the book - they are simpler while respecting the same interface. //////////////////////////////////////////////////////////////////////////////// namespace Loki { //////////////////////////////////////////////////////////////////////////////// // Implementation helpers for StaticDispatcher //////////////////////////////////////////////////////////////////////////////// namespace Private { template struct InvocationTraits { static ResultType DoDispatch(SomeLhs& lhs, SomeRhs& rhs, Executor& exec, Int2Type) { return exec.Fire(lhs, rhs); } static ResultType DoDispatch( SomeLhs& lhs, SomeRhs& rhs, Executor& exec, Int2Type) { return exec.Fire(rhs, lhs); } }; template struct InvocationTraitsVoid { typedef void ResultType; static ResultType DoDispatch(SomeLhs& lhs, SomeRhs& rhs, Executor& exec, Int2Type) { exec.Fire(lhs, rhs); } static ResultType DoDispatch( SomeLhs& lhs, SomeRhs& rhs, Executor& exec, Int2Type) { exec.Fire(rhs, lhs); } }; // Implementation for StaticDispatcher with result type != void template class StaticDispatcherBase { template static ResultType DispatchRhs( SomeLhs& lhs, BaseRhs& rhs, Executor exec, NullType) { return exec.OnError(lhs, rhs); } template static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs, Executor exec, Typelist) { if (Head* p2 = dynamic_cast(&rhs)) { Int2Type<(symmetric && int(TL::IndexOf::value) < int(TL::IndexOf::value))> i2t; typedef Private::InvocationTraits< SomeLhs, Head, Executor, ResultType> CallTraits; return CallTraits::DoDispatch(lhs, *p2, exec, i2t); } return DispatchRhs(lhs, rhs, exec, Tail()); } static ResultType DispatchLhs( BaseLhs& lhs, BaseRhs& rhs, Executor exec, NullType) { return exec.OnError(lhs, rhs); } template static ResultType DispatchLhs( BaseLhs& lhs, BaseRhs& rhs, Executor exec, Typelist) { if (Head* p1 = dynamic_cast(&lhs)) { return DispatchRhs(*p1, rhs, exec, TypesRhs()); } return DispatchLhs(lhs, rhs, exec, Tail()); } public: static ResultType Go( BaseLhs& lhs, BaseRhs& rhs, Executor exec) { return DispatchLhs(lhs, rhs, exec, TypesLhs()); } }; // Implementation for StaticDispatcher with result type = void template class StaticDispatcherVoidBase { typedef void ResultType; template static ResultType DispatchRhs( SomeLhs& lhs, BaseRhs& rhs, Executor exec, NullType) { exec.OnError(lhs, rhs); } template static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs, Executor exec, Typelist) { if (Head* p2 = dynamic_cast(&rhs)) { Int2Type<(symmetric && int(TL::IndexOf::value) < int(TL::IndexOf::value))> i2t; typedef Private::InvocationTraitsVoid< SomeLhs, Head, Executor> CallTraits; CallTraits::DoDispatch(lhs, *p2, exec, i2t); return; } DispatchRhs(lhs, rhs, exec, Tail()); } static ResultType DispatchLhs( BaseLhs& lhs, BaseRhs& rhs, Executor exec, NullType) { exec.OnError(lhs, rhs); } template static ResultType DispatchLhs( BaseLhs& lhs, BaseRhs& rhs, Executor exec, Typelist) { if (Head* p1 = dynamic_cast(&lhs)) { DispatchRhs(*p1, rhs, exec, TypesRhs()); return; } DispatchLhs(lhs, rhs, exec, Tail()); } public: static ResultType Go( BaseLhs& lhs, BaseRhs& rhs, Executor exec) { DispatchLhs(lhs, rhs, exec, TypesLhs()); } }; } // namespace Private //////////////////////////////////////////////////////////////////////////////// // class template StaticDispatcher // Implements an automatic static double dispatcher based on two typelists //////////////////////////////////////////////////////////////////////////////// template < class Executor, class BaseLhs, class TypesLhs, bool symmetric = true, class BaseRhs = BaseLhs, class TypesRhs = TypesLhs, typename ResultType = int > class StaticDispatcher : public ::Loki::Select < ::Loki::Private::IsVoid::value, ::Loki::Private::StaticDispatcherVoidBase, ::Loki::Private::StaticDispatcherBase >::Result { public: // member functions moved to base class // static ResultType Go( BaseLhs& lhs, BaseRhs& rhs, // Executor exec) }; //////////////////////////////////////////////////////////////////////////////// // Implementation helpers for BasicDispatcher //////////////////////////////////////////////////////////////////////////////// namespace Private { // Implementation for result types != void template struct BasicDispatcherBase; // Implementation for result type = 0 template struct BasicDispatcherVoidBase; // Common (independent of the result type) code for BasicDispatcher template class BasicDispatcherCommonBase { private: void DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun); bool DoRemove(TypeInfo lhs, TypeInfo rhs); protected: typedef std::pair KeyType; typedef CallbackType MappedType; typedef AssocVector MapType; MapType callbackMap_; public: template void Add(CallbackType fun, ::Loki::Type2Type, ::Loki::Type2Type) { DoAdd(typeid(SomeLhs), typeid(SomeRhs), fun); } template bool Remove(::Loki::Type2Type, ::Loki::Type2Type) { return DoRemove(typeid(SomeLhs), typeid(SomeRhs)); } }; // Non-inline to reduce compile time overhead... template void BasicDispatcherCommonBase ::DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun) { callbackMap_[KeyType(lhs, rhs)] = fun; } template bool BasicDispatcherCommonBase ::DoRemove(TypeInfo lhs, TypeInfo rhs) { return callbackMap_.erase(KeyType(lhs, rhs)) == 1; } // Implementation for result types != void template struct BasicDispatcherBase : public BasicDispatcherCommonBase { typedef BasicDispatcherCommonBase Base; ResultType Go(BaseLhs& lhs, BaseRhs& rhs); }; template ResultType BasicDispatcherBase ::Go(BaseLhs& lhs, BaseRhs& rhs) { typename MapType::key_type k(typeid(lhs),typeid(rhs)); typename MapType::iterator i = Base::callbackMap_.find(k); if (i == Base::callbackMap_.end()) { throw std::runtime_error("Function not found"); } return (i->second)(lhs, rhs); } // Implementation for result types = void template struct BasicDispatcherVoidBase : public BasicDispatcherCommonBase { typedef void ResultType; typedef BasicDispatcherCommonBase Base; ResultType Go(BaseLhs& lhs, BaseRhs& rhs); }; template typename BasicDispatcherVoidBase::ResultType BasicDispatcherVoidBase ::Go(BaseLhs& lhs, BaseRhs& rhs) { typename MapType::key_type k(typeid(lhs),typeid(rhs)); typename MapType::iterator i = Base::callbackMap_.find(k); if (i == Base::callbackMap_.end()) { throw std::runtime_error("Function not found"); } (i->second)(lhs, rhs); } } // namespace Private //////////////////////////////////////////////////////////////////////////////// // class template BasicDispatcher // Implements a logarithmic double dispatcher for functors (or functions) // Doesn't offer automated casts or symmetry //////////////////////////////////////////////////////////////////////////////// template < class BaseLhs, class BaseRhs = BaseLhs, typename ResultType = int, typename CallbackType = ResultType (*)(BaseLhs&, BaseRhs&) > class BasicDispatcher : public ::Loki::Select < ::Loki::Private::IsVoid::value, ::Loki::Private::BasicDispatcherVoidBase< BaseLhs, BaseRhs, CallbackType>, ::Loki::Private::BasicDispatcherBase< BaseLhs, BaseRhs, ResultType, CallbackType> >::Result { public: // member functions moved to base class // template // void Add(CallbackType fun, ::Loki::Type2Type, // ::Loki::Type2Type) // // template // bool Remove(::Loki::Type2Type, ::Loki::Type2Type) // // ResultType Go(BaseLhs& lhs, BaseRhs& rhs); }; struct BasicDispatcherWrapper { template struct In { typedef BasicDispatcher type; }; }; //////////////////////////////////////////////////////////////////////////////// // class template StaticCaster // Implementation of the CastingPolicy used by FunctorDispatcher //////////////////////////////////////////////////////////////////////////////// template struct StaticCaster { static To& Cast(From& obj) { return static_cast(obj); } }; struct StaticCasterWrapper { template struct In { typedef StaticCaster type; }; }; //////////////////////////////////////////////////////////////////////////////// // class template DynamicCaster // Implementation of the CastingPolicy used by FunctorDispatcher //////////////////////////////////////////////////////////////////////////////// template struct DynamicCaster { static To& Cast(From& obj) { return dynamic_cast(obj); } }; struct DynamicCasterWrapper { template struct In { typedef DynamicCaster type; }; }; //////////////////////////////////////////////////////////////////////////////// // class template Private::FnDispatcherHelper // Implements trampolines and argument swapping used by FnDispatcher //////////////////////////////////////////////////////////////////////////////// namespace Private { template struct FnDispatcherBase { ApplyInnerType4::type backEnd_; ResultType Go(BaseLhs& lhs, BaseRhs& rhs) { return backEnd_.Go(lhs, rhs); } }; template struct FnDispatcherVoidBase { typedef void ResultType; ApplyInnerType4::type backEnd_; ResultType Go(BaseLhs& lhs, BaseRhs& rhs) { backEnd_.Go(lhs, rhs); } }; template< class BaseLhs, class BaseRhs, class SomeLhs, class SomeRhs, class CastLhs, class CastRhs, void (*Callback)(SomeLhs&, SomeRhs&)> struct FnDispatcherHelperVoidBase { typedef void ResultType; static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs) { Callback(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); } static ResultType TrampolineR(BaseRhs& rhs, BaseLhs& lhs) { Trampoline(lhs, rhs); } }; template struct FnDispatcherHelperBase { typedef void ResultType; static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs) { Callback(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); } static ResultType TrampolineR(BaseRhs& rhs, BaseLhs& lhs) { Trampoline(lhs, rhs); } }; template < class BaseLhs, class BaseRhs, class SomeLhs, class SomeRhs, typename ResultType, class CastLhs, class CastRhs, ResultType (*Callback)(SomeLhs&, SomeRhs&) > struct FnDispatcherHelper : public ::Loki::Select < ::Loki::Private::IsVoid::value, FnDispatcherHelperVoidBase, FnDispatcherHelperBase >::Result {}; } //////////////////////////////////////////////////////////////////////////////// // class template FnDispatcher // Implements an automatic logarithmic double dispatcher for functions // Features automated conversions //////////////////////////////////////////////////////////////////////////////// template class FnDispatcher : public ::Loki::Select < ::Loki::Private::IsVoid::value, ::Loki::Private::FnDispatcherVoidBase, ::Loki::Private::FnDispatcherBase >::Result { typedef typename ::Loki::Select <::Loki::Private::IsVoid::value, ::Loki::Private::FnDispatcherVoidBase, ::Loki::Private::FnDispatcherBase >::Result Base; public: template void Add(ResultType (*pFun)(BaseLhs&, BaseRhs&), ::Loki::Type2Type, ::Loki::Type2Type) { Base::backEnd_.Add(pFun, ::Loki::Type2Type(), ::Loki::Type2Type()); } template void Add(::Loki::Type2Type, ::Loki::Type2Type) { typedef Private::FnDispatcherHelper< BaseLhs, BaseRhs, SomeLhs, SomeRhs, ResultType, typename ApplyInnerType2::type, typename ApplyInnerType2::type, callback> Local; Add(&Local::Trampoline, ::Loki::Type2Type(), ::Loki::Type2Type()); } template void Add(::Loki::Type2Type, ::Loki::Type2Type, bool Symmetric) { typedef Private::FnDispatcherHelper< BaseLhs, BaseRhs, SomeLhs, SomeRhs, ResultType, typename ApplyInnerType2::type, typename ApplyInnerType2::type, callback> Local; Add(&Local::Trampoline, ::Loki::Type2Type(), ::Loki::Type2Type()); if (Symmetric) { Add(&Local::Trampoline, ::Loki::Type2Type(), ::Loki::Type2Type()); } } template void Remove(::Loki::Type2Type, ::Loki::Type2Type) { Base::backEnd_.Remove(::Loki::Type2Type(), ::Loki::Type2Type()); } // moved to base class // ResultType Go(BaseLhs& lhs, BaseRhs& rhs); }; //////////////////////////////////////////////////////////////////////////////// // class template FunctorDispatcherAdaptor // permits use of FunctorDispatcher under gcc.2.95.2/3 /////////////////////////////////////////////////////////////////////////////// namespace Private { template class FunctorDispatcherHelper { Fun fun_; ResultType Fire(BaseLhs& lhs, BaseRhs& rhs,Int2Type) { return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); } ResultType Fire(BaseLhs& rhs, BaseRhs& lhs,Int2Type) { return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); } public: FunctorDispatcherHelper(const Fun& fun) : fun_(fun) {} ResultType operator()(BaseLhs& lhs, BaseRhs& rhs) { return Fire(lhs,rhs,Int2Type()); } }; template class FunctorDispatcherHelperVoid { Fun fun_; typedef void ResultType; ResultType Fire(BaseLhs& lhs, BaseRhs& rhs,Int2Type) { fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); } ResultType Fire(BaseLhs& rhs, BaseRhs& lhs,Int2Type) { fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); } public: FunctorDispatcherHelperVoid(const Fun& fun) : fun_(fun) {} ResultType operator()(BaseLhs& lhs, BaseRhs& rhs) { Fire(lhs,rhs,Int2Type()); } }; template class FunctorDispatcherCommonBase { protected: typedef TYPELIST_2(BaseLhs&, BaseRhs&) ArgsList; typedef Functor FunctorType; ApplyInnerType4::type backEnd_; }; template class FunctorDispatcherBase : public FunctorDispatcherCommonBase { typedef FunctorDispatcherCommonBase Base; public: typedef typename Base::ArgsList ArgsList; typedef typename Base::FunctorType FunctorType; ResultType Go(BaseLhs& lhs, BaseRhs& rhs) { return Base::backEnd_.Go(lhs, rhs); } }; template class FunctorDispatcherVoidBase : public FunctorDispatcherCommonBase { typedef void ResultType; typedef FunctorDispatcherCommonBase Base; public: typedef typename Base::ArgsList ArgsList; typedef typename Base::FunctorType FunctorType; ResultType Go(BaseLhs& lhs, BaseRhs& rhs) { Base::backEnd_.Go(lhs, rhs); } }; } //////////////////////////////////////////////////////////////////////////////// // class template FunctorDispatcher // Implements a logarithmic double dispatcher for functors // Features automated casting //////////////////////////////////////////////////////////////////////////////// template class FunctorDispatcher : public ::Loki::Select < ::Loki::Private::IsVoid::value, ::Loki::Private::FunctorDispatcherVoidBase, ::Loki::Private::FunctorDispatcherBase >::Result { typedef typename ::Loki::Select < ::Loki::Private::IsVoid::value, ::Loki::Private::FunctorDispatcherVoidBase, ::Loki::Private::FunctorDispatcherBase >::Result Base; public: typedef Base::ArgsList ArgsList; typedef Base::FunctorType FunctorType; template void Add(const Fun& fun, ::Loki::Type2Type, ::Loki::Type2Type) { typedef typename ApplyInnerType2::type CastOne; typedef typename ApplyInnerType2::type CastTwo; typedef typename Select< Private::IsVoid::value, Private::FunctorDispatcherHelperVoid, Private::FunctorDispatcherHelper >::Result Adapter; Base::backEnd_.Add(FunctorType(Adapter(fun), Loki::Disambiguate()), Type2Type(), Type2Type()); } template void Add(const Fun& fun, ::Loki::Type2Type, ::Loki::Type2Type, bool symmetric) { Add(fun, Type2Type(), Type2Type()); if (symmetric) { // Note: symmetry only makes sense where BaseLhs==BaseRhs typedef typename ApplyInnerType2::type CastOne; typedef typename ApplyInnerType2::type CastTwo; typedef typename Select::value, Private::FunctorDispatcherHelperVoid, Private::FunctorDispatcherHelper >::Result AdapterR; Base::backEnd_.Add(FunctorType(Adapter(fun)), Type2Type(), Type2Type()); } } template void Remove(::Loki::Type2Type, ::Loki::Type2Type) { Base::backEnd_.Remove(Type2Type(), Type2Type()); } // moved to base class // ResultType Go(BaseLhs& lhs, BaseRhs& rhs); }; } // namespace Loki //////////////////////////////////////////////////////////////////////////////// // Change log: // June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!! // May 10, 2002: ported by Rani Sharoni to VC7 (RTM - 9466) // Oct 28, 2002: ported by Benjamin Kaufmann // Feb 19, 2003: replaced pointer-Dummies with Type2Type-Parameters and added // support for return type void. //////////////////////////////////////////////////////////////////////////////// #endif