//////////////////////////////////////////////////////////////////////////////// // 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-Wesley Longman make no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// #ifndef LOKI_MULTIMETHODS_INC_ #define LOKI_MULTIMETHODS_INC_ // $Id: MultiMethods.h 751 2006-10-17 19:50:37Z syntheticpp $ #include "Typelist.h" #include "LokiTypeInfo.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 { //////////////////////////////////////////////////////////////////////////////// // class template InvocationTraits (helper) // Helps implementing optional symmetry //////////////////////////////////////////////////////////////////////////////// namespace Private { template <class SomeLhs, class SomeRhs, class Executor, typename ResultType> struct InvocationTraits { static ResultType DoDispatch(SomeLhs& lhs, SomeRhs& rhs, Executor& exec, Int2Type<false>) { return exec.Fire(lhs, rhs); } static ResultType DoDispatch(SomeLhs& lhs, SomeRhs& rhs, Executor& exec, Int2Type<true>) { return exec.Fire(rhs, lhs); } }; } //////////////////////////////////////////////////////////////////////////////// // 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 = void > class StaticDispatcher { template <class SomeLhs> static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs, Executor exec, NullType) { return exec.OnError(lhs, rhs); } template <class Head, class Tail, class SomeLhs> static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs, Executor exec, Typelist<Head, Tail>) { if (Head* p2 = dynamic_cast<Head*>(&rhs)) { Int2Type<(symmetric && int(TL::IndexOf<TypesRhs, Head>::value) < int(TL::IndexOf<TypesLhs, SomeLhs>::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 <class Head, class Tail> static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs, Executor exec, Typelist<Head, Tail>) { if (Head* p1 = dynamic_cast<Head*>(&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()); } }; //////////////////////////////////////////////////////////////////////////////// // 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 = void, typename CallbackType = ResultType (*)(BaseLhs&, BaseRhs&) > class BasicDispatcher { typedef std::pair<TypeInfo,TypeInfo> KeyType; typedef CallbackType MappedType; typedef AssocVector<KeyType, MappedType> MapType; MapType callbackMap_; void DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun); bool DoRemove(TypeInfo lhs, TypeInfo rhs); public: template <class SomeLhs, class SomeRhs> void Add(CallbackType fun) { DoAdd(typeid(SomeLhs), typeid(SomeRhs), fun); } template <class SomeLhs, class SomeRhs> bool Remove() { return DoRemove(typeid(SomeLhs), typeid(SomeRhs)); } ResultType Go(BaseLhs& lhs, BaseRhs& rhs); }; // Non-inline to reduce compile time overhead... template <class BaseLhs, class BaseRhs, typename ResultType, typename CallbackType> void BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType> ::DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun) { callbackMap_[KeyType(lhs, rhs)] = fun; } template <class BaseLhs, class BaseRhs, typename ResultType, typename CallbackType> bool BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType> ::DoRemove(TypeInfo lhs, TypeInfo rhs) { return callbackMap_.erase(KeyType(lhs, rhs)) == 1; } template <class BaseLhs, class BaseRhs, typename ResultType, typename CallbackType> ResultType BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType> ::Go(BaseLhs& lhs, BaseRhs& rhs) { typename MapType::key_type k(typeid(lhs),typeid(rhs)); typename MapType::iterator i = callbackMap_.find(k); if (i == callbackMap_.end()) { throw std::runtime_error("Function not found"); } return (i->second)(lhs, rhs); } //////////////////////////////////////////////////////////////////////////////// // class template StaticCaster // Implementation of the CastingPolicy used by FunctorDispatcher //////////////////////////////////////////////////////////////////////////////// template <class To, class From> struct StaticCaster { static To& Cast(From& obj) { return static_cast<To&>(obj); } }; //////////////////////////////////////////////////////////////////////////////// // class template DynamicCaster // Implementation of the CastingPolicy used by FunctorDispatcher //////////////////////////////////////////////////////////////////////////////// template <class To, class From> struct DynamicCaster { static To& Cast(From& obj) { return dynamic_cast<To&>(obj); } }; //////////////////////////////////////////////////////////////////////////////// // class template Private::FnDispatcherHelper // Implements trampolines and argument swapping used by FnDispatcher //////////////////////////////////////////////////////////////////////////////// namespace Private { template <class BaseLhs, class BaseRhs, class SomeLhs, class SomeRhs, typename ResultType, class CastLhs, class CastRhs, ResultType (*Callback)(SomeLhs&, SomeRhs&)> struct FnDispatcherHelper { static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs) { return Callback(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); } static ResultType TrampolineR(BaseRhs& rhs, BaseLhs& lhs) { return Trampoline(lhs, rhs); } }; } //////////////////////////////////////////////////////////////////////////////// // class template FnDispatcher // Implements an automatic logarithmic double dispatcher for functions // Features automated conversions //////////////////////////////////////////////////////////////////////////////// template <class BaseLhs, class BaseRhs = BaseLhs, typename ResultType = void, template <class, class> class CastingPolicy = DynamicCaster, template <class, class, class, class> class DispatcherBackend = BasicDispatcher> class FnDispatcher { DispatcherBackend<BaseLhs, BaseRhs, ResultType, ResultType (*)(BaseLhs&, BaseRhs&)> backEnd_; public: template <class SomeLhs, class SomeRhs> void Add(ResultType (*pFun)(BaseLhs&, BaseRhs&)) { return backEnd_.template Add<SomeLhs, SomeRhs>(pFun); } template <class SomeLhs, class SomeRhs, ResultType (*callback)(SomeLhs&, SomeRhs&)> void Add() { typedef Private::FnDispatcherHelper< BaseLhs, BaseRhs, SomeLhs, SomeRhs, ResultType, CastingPolicy<SomeLhs,BaseLhs>, CastingPolicy<SomeRhs,BaseRhs>, callback> Local; Add<SomeLhs, SomeRhs>(&Local::Trampoline); } template <class SomeLhs, class SomeRhs, ResultType (*callback)(SomeLhs&, SomeRhs&), bool symmetric> void Add(bool = true) // [gcc] dummy bool { typedef Private::FnDispatcherHelper< BaseLhs, BaseRhs, SomeLhs, SomeRhs, ResultType, CastingPolicy<SomeLhs,BaseLhs>, CastingPolicy<SomeRhs,BaseRhs>, callback> Local; Add<SomeLhs, SomeRhs>(&Local::Trampoline); if (symmetric) { Add<SomeRhs, SomeLhs>(&Local::TrampolineR); } } template <class SomeLhs, class SomeRhs> void Remove() { backEnd_.template Remove<SomeLhs, SomeRhs>(); } ResultType Go(BaseLhs& lhs, BaseRhs& rhs) { return backEnd_.Go(lhs, rhs); } }; //////////////////////////////////////////////////////////////////////////////// // class template FunctorDispatcherAdaptor // permits use of FunctorDispatcher under gcc.2.95.2/3 /////////////////////////////////////////////////////////////////////////////// namespace Private { template <class BaseLhs, class BaseRhs, class SomeLhs, class SomeRhs, typename ResultType, class CastLhs, class CastRhs, class Fun, bool SwapArgs> class FunctorDispatcherHelper { Fun fun_; ResultType Fire(BaseLhs& lhs, BaseRhs& rhs,Int2Type<false>) { return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); } ResultType Fire(BaseLhs& rhs, BaseRhs& lhs,Int2Type<true>) { 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<SwapArgs>()); } }; } //////////////////////////////////////////////////////////////////////////////// // class template FunctorDispatcher // Implements a logarithmic double dispatcher for functors // Features automated casting //////////////////////////////////////////////////////////////////////////////// template <class BaseLhs, class BaseRhs = BaseLhs, typename ResultType = void, template <class, class> class CastingPolicy = DynamicCaster, template <class, class, class, class> class DispatcherBackend = BasicDispatcher> class FunctorDispatcher { typedef LOKI_TYPELIST_2(BaseLhs&, BaseRhs&) ArgsList; typedef Functor<ResultType, ArgsList, LOKI_DEFAULT_THREADING> FunctorType; DispatcherBackend<BaseLhs, BaseRhs, ResultType, FunctorType> backEnd_; public: template <class SomeLhs, class SomeRhs, class Fun> void Add(const Fun& fun) { typedef Private::FunctorDispatcherHelper< BaseLhs, BaseRhs, SomeLhs, SomeRhs, ResultType, CastingPolicy<SomeLhs, BaseLhs>, CastingPolicy<SomeRhs, BaseRhs>, Fun, false> Adapter; backEnd_.template Add<SomeLhs, SomeRhs>(FunctorType(Adapter(fun))); } template <class SomeLhs, class SomeRhs, bool symmetric, class Fun> void Add(const Fun& fun) { Add<SomeLhs,SomeRhs>(fun); if (symmetric) { // Note: symmetry only makes sense where BaseLhs==BaseRhs typedef Private::FunctorDispatcherHelper< BaseLhs, BaseLhs, SomeLhs, SomeRhs, ResultType, CastingPolicy<SomeLhs, BaseLhs>, CastingPolicy<SomeRhs, BaseLhs>, Fun, true> AdapterR; backEnd_.template Add<SomeRhs, SomeLhs>(FunctorType(AdapterR(fun))); } } template <class SomeLhs, class SomeRhs> void Remove() { backEnd_.template Remove<SomeLhs, SomeRhs>(); } ResultType Go(BaseLhs& lhs, BaseRhs& rhs) { return backEnd_.Go(lhs, rhs); } }; } // namespace Loki #endif // end file guardian