c5ca330861
git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@30 7ec92016-0320-0410-acc4-a06ded1c099a
447 lines
14 KiB
C++
447 lines
14 KiB
C++
head 1.1;
|
||
access;
|
||
symbols;
|
||
locks; strict;
|
||
comment @ * @;
|
||
|
||
|
||
1.1
|
||
date 2002.07.16.22.42.05; author tslettebo; state Exp;
|
||
branches;
|
||
next ;
|
||
|
||
|
||
desc
|
||
@@
|
||
|
||
|
||
1.1
|
||
log
|
||
@Initial commit
|
||
@
|
||
text
|
||
@////////////////////////////////////////////////////////////////////////////////
|
||
// 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.
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
// Last update: June 20, 2001
|
||
|
||
#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
|
||
{
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// 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 TList, class SomeLhs>
|
||
static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs,
|
||
Executor exec, TList)
|
||
{
|
||
typedef typename TList::Head Head;
|
||
typedef typename TList::Tail 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 TList>
|
||
static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs,
|
||
Executor exec, TList)
|
||
{
|
||
typedef typename TList::Head Head;
|
||
typedef typename TList::Tail 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_.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()
|
||
{
|
||
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_.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 TYPELIST_2(BaseLhs&, BaseRhs&) ArgsList;
|
||
typedef Functor<ResultType, ArgsList, 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_.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_.Add<SomeRhs, SomeLhs>(FunctorType(AdapterR(fun)));
|
||
}
|
||
}
|
||
|
||
template <class SomeLhs, class SomeRhs>
|
||
void Remove()
|
||
{
|
||
backEnd_.Remove<SomeLhs, SomeRhs>();
|
||
}
|
||
|
||
ResultType Go(BaseLhs& lhs, BaseRhs& rhs)
|
||
{
|
||
return backEnd_.Go(lhs, rhs);
|
||
}
|
||
};
|
||
} // namespace Loki
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// Change log:
|
||
// June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!!
|
||
// July 16, 2002: Ported by Terje Sletteb<65> to BCC 5.6
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
#endif
|
||
@
|