summaryrefslogtreecommitdiff
path: root/shared/loki/MultiMethods.h
diff options
context:
space:
mode:
Diffstat (limited to 'shared/loki/MultiMethods.h')
-rw-r--r--shared/loki/MultiMethods.h415
1 files changed, 415 insertions, 0 deletions
diff --git a/shared/loki/MultiMethods.h b/shared/loki/MultiMethods.h
new file mode 100644
index 00000000..d095cfae
--- /dev/null
+++ b/shared/loki/MultiMethods.h
@@ -0,0 +1,415 @@
+////////////////////////////////////////////////////////////////////////////////
+// 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
+
bgstack15