diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:01:29 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:01:29 +0200 |
commit | 9a2a524f1e311853d08050be2dcdddc09ac7759a (patch) | |
tree | d8e4a24169fce88c2d89931d58514889a0bcb0ea /shared/loki/MultiMethods.h | |
parent | 2.3 (diff) | |
download | FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.tar.gz FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.tar.bz2 FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.zip |
3.0
Diffstat (limited to 'shared/loki/MultiMethods.h')
-rw-r--r-- | shared/loki/MultiMethods.h | 415 |
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 + |