1 ////////////////////////////////////////////////////////////////////////////////
3 // Copyright (c) 2001 by Andrei Alexandrescu
4 // This code accompanies the book:
5 // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design
6 // Patterns Applied". Copyright (c) 2001. Addison-Wesley.
7 // Permission to use, copy, modify, distribute and sell this software for any
8 // purpose is hereby granted without fee, provided that the above copyright
9 // notice appear in all copies and that both that copyright notice and this
10 // permission notice appear in supporting documentation.
11 // The author or Addison-Wesley Longman make no representations about the
12 // suitability of this software for any purpose. It is provided "as is"
13 // without express or implied warranty.
14 ////////////////////////////////////////////////////////////////////////////////
15 #ifndef LOKI_MULTIMETHODS_INC_
16 #define LOKI_MULTIMETHODS_INC_
18 // $Id: MultiMethods.h 751 2006-10-17 19:50:37Z syntheticpp $
22 #include "LokiTypeInfo.h"
24 #include "AssocVector.h"
26 ////////////////////////////////////////////////////////////////////////////////
28 // The double dispatchers implemented below differ from the excerpts shown in
29 // the book - they are simpler while respecting the same interface.
30 ////////////////////////////////////////////////////////////////////////////////
34 ////////////////////////////////////////////////////////////////////////////////
35 // class template InvocationTraits (helper)
36 // Helps implementing optional symmetry
37 ////////////////////////////////////////////////////////////////////////////////
41 template <class SomeLhs, class SomeRhs,
42 class Executor, typename ResultType>
43 struct InvocationTraits
46 DoDispatch(SomeLhs &lhs, SomeRhs &rhs,
47 Executor &exec, Int2Type<false>)
49 return exec.Fire(lhs, rhs);
52 DoDispatch(SomeLhs &lhs, SomeRhs &rhs,
53 Executor &exec, Int2Type<true>)
55 return exec.Fire(rhs, lhs);
60 ////////////////////////////////////////////////////////////////////////////////
61 // class template StaticDispatcher
62 // Implements an automatic static double dispatcher based on two typelists
63 ////////////////////////////////////////////////////////////////////////////////
70 bool symmetric = true,
71 class BaseRhs = BaseLhs,
72 class TypesRhs = TypesLhs,
73 typename ResultType = void
75 class StaticDispatcher
77 template <class SomeLhs>
78 static ResultType DispatchRhs(SomeLhs &lhs, BaseRhs &rhs,
79 Executor exec, NullType)
81 return exec.OnError(lhs, rhs);
84 template <class Head, class Tail, class SomeLhs>
85 static ResultType DispatchRhs(SomeLhs &lhs, BaseRhs &rhs,
86 Executor exec, Typelist<Head, Tail>)
88 if (Head *p2 = dynamic_cast<Head *>(&rhs))
90 Int2Type<(symmetric &&
91 int(TL::IndexOf<TypesRhs, Head>::value) <
92 int(TL::IndexOf<TypesLhs, SomeLhs>::value))> i2t;
94 typedef Private::InvocationTraits<
95 SomeLhs, Head, Executor, ResultType> CallTraits;
97 return CallTraits::DoDispatch(lhs, *p2, exec, i2t);
99 return DispatchRhs(lhs, rhs, exec, Tail());
102 static ResultType DispatchLhs(BaseLhs &lhs, BaseRhs &rhs,
103 Executor exec, NullType)
105 return exec.OnError(lhs, rhs);
108 template <class Head, class Tail>
109 static ResultType DispatchLhs(BaseLhs &lhs, BaseRhs &rhs,
110 Executor exec, Typelist<Head, Tail>)
112 if (Head *p1 = dynamic_cast<Head *>(&lhs))
114 return DispatchRhs(*p1, rhs, exec, TypesRhs());
116 return DispatchLhs(lhs, rhs, exec, Tail());
120 static ResultType Go(BaseLhs &lhs, BaseRhs &rhs,
123 return DispatchLhs(lhs, rhs, exec, TypesLhs());
127 ////////////////////////////////////////////////////////////////////////////////
128 // class template BasicDispatcher
129 // Implements a logarithmic double dispatcher for functors (or functions)
130 // Doesn't offer automated casts or symmetry
131 ////////////////////////////////////////////////////////////////////////////////
136 class BaseRhs = BaseLhs,
137 typename ResultType = void,
138 typename CallbackType = ResultType ( *)(BaseLhs &, BaseRhs &)
140 class BasicDispatcher
142 typedef std::pair<TypeInfo,TypeInfo> KeyType;
143 typedef CallbackType MappedType;
144 typedef AssocVector<KeyType, MappedType> MapType;
145 MapType callbackMap_;
147 void DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun);
148 bool DoRemove(TypeInfo lhs, TypeInfo rhs);
151 template <class SomeLhs, class SomeRhs>
152 void Add(CallbackType fun)
154 DoAdd(typeid(SomeLhs), typeid(SomeRhs), fun);
157 template <class SomeLhs, class SomeRhs>
160 return DoRemove(typeid(SomeLhs), typeid(SomeRhs));
163 ResultType Go(BaseLhs &lhs, BaseRhs &rhs);
166 // Non-inline to reduce compile time overhead...
167 template <class BaseLhs, class BaseRhs,
168 typename ResultType, typename CallbackType>
169 void BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
170 ::DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun)
172 callbackMap_[KeyType(lhs, rhs)] = fun;
175 template <class BaseLhs, class BaseRhs,
176 typename ResultType, typename CallbackType>
177 bool BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
178 ::DoRemove(TypeInfo lhs, TypeInfo rhs)
180 return callbackMap_.erase(KeyType(lhs, rhs)) == 1;
183 template <class BaseLhs, class BaseRhs,
184 typename ResultType, typename CallbackType>
185 ResultType BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType>
186 ::Go(BaseLhs &lhs, BaseRhs &rhs)
188 typename MapType::key_type k(typeid(lhs),typeid(rhs));
189 typename MapType::iterator i = callbackMap_.find(k);
190 if (i == callbackMap_.end())
192 throw std::runtime_error("Function not found");
194 return (i->second)(lhs, rhs);
197 ////////////////////////////////////////////////////////////////////////////////
198 // class template StaticCaster
199 // Implementation of the CastingPolicy used by FunctorDispatcher
200 ////////////////////////////////////////////////////////////////////////////////
202 template <class To, class From>
205 static To &Cast(From &obj)
207 return static_cast<To &>(obj);
211 ////////////////////////////////////////////////////////////////////////////////
212 // class template DynamicCaster
213 // Implementation of the CastingPolicy used by FunctorDispatcher
214 ////////////////////////////////////////////////////////////////////////////////
216 template <class To, class From>
219 static To &Cast(From &obj)
221 return dynamic_cast<To &>(obj);
225 ////////////////////////////////////////////////////////////////////////////////
226 // class template Private::FnDispatcherHelper
227 // Implements trampolines and argument swapping used by FnDispatcher
228 ////////////////////////////////////////////////////////////////////////////////
232 template <class BaseLhs, class BaseRhs,
233 class SomeLhs, class SomeRhs,
235 class CastLhs, class CastRhs,
236 ResultType (*Callback)(SomeLhs &, SomeRhs &)>
237 struct FnDispatcherHelper
239 static ResultType Trampoline(BaseLhs &lhs, BaseRhs &rhs)
241 return Callback(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
243 static ResultType TrampolineR(BaseRhs &rhs, BaseLhs &lhs)
245 return Trampoline(lhs, rhs);
250 ////////////////////////////////////////////////////////////////////////////////
251 // class template FnDispatcher
252 // Implements an automatic logarithmic double dispatcher for functions
253 // Features automated conversions
254 ////////////////////////////////////////////////////////////////////////////////
256 template <class BaseLhs, class BaseRhs = BaseLhs,
257 typename ResultType = void,
258 template <class, class> class CastingPolicy = DynamicCaster,
259 template <class, class, class, class>
260 class DispatcherBackend = BasicDispatcher>
263 DispatcherBackend<BaseLhs, BaseRhs, ResultType,
264 ResultType ( *)(BaseLhs &, BaseRhs &)> backEnd_;
267 template <class SomeLhs, class SomeRhs>
268 void Add(ResultType (*pFun)(BaseLhs &, BaseRhs &))
270 return backEnd_.template Add<SomeLhs, SomeRhs>(pFun);
273 template <class SomeLhs, class SomeRhs,
274 ResultType (*callback)(SomeLhs &, SomeRhs &)>
277 typedef Private::FnDispatcherHelper<
281 CastingPolicy<SomeLhs,BaseLhs>,
282 CastingPolicy<SomeRhs,BaseRhs>,
285 Add<SomeLhs, SomeRhs>(&Local::Trampoline);
288 template <class SomeLhs, class SomeRhs,
289 ResultType (*callback)(SomeLhs &, SomeRhs &),
291 void Add(bool = true) // [gcc] dummy bool
293 typedef Private::FnDispatcherHelper<
297 CastingPolicy<SomeLhs,BaseLhs>,
298 CastingPolicy<SomeRhs,BaseRhs>,
301 Add<SomeLhs, SomeRhs>(&Local::Trampoline);
304 Add<SomeRhs, SomeLhs>(&Local::TrampolineR);
308 template <class SomeLhs, class SomeRhs>
311 backEnd_.template Remove<SomeLhs, SomeRhs>();
314 ResultType Go(BaseLhs &lhs, BaseRhs &rhs)
316 return backEnd_.Go(lhs, rhs);
320 ////////////////////////////////////////////////////////////////////////////////
321 // class template FunctorDispatcherAdaptor
322 // permits use of FunctorDispatcher under gcc.2.95.2/3
323 ///////////////////////////////////////////////////////////////////////////////
327 template <class BaseLhs, class BaseRhs,
328 class SomeLhs, class SomeRhs,
330 class CastLhs, class CastRhs,
331 class Fun, bool SwapArgs>
332 class FunctorDispatcherHelper
335 ResultType Fire(BaseLhs &lhs, BaseRhs &rhs,Int2Type<false>)
337 return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
339 ResultType Fire(BaseLhs &rhs, BaseRhs &lhs,Int2Type<true>)
341 return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs));
344 FunctorDispatcherHelper(const Fun &fun) : fun_(fun) {}
346 ResultType operator()(BaseLhs &lhs, BaseRhs &rhs)
348 return Fire(lhs,rhs,Int2Type<SwapArgs>());
353 ////////////////////////////////////////////////////////////////////////////////
354 // class template FunctorDispatcher
355 // Implements a logarithmic double dispatcher for functors
356 // Features automated casting
357 ////////////////////////////////////////////////////////////////////////////////
359 template <class BaseLhs, class BaseRhs = BaseLhs,
360 typename ResultType = void,
361 template <class, class> class CastingPolicy = DynamicCaster,
362 template <class, class, class, class>
363 class DispatcherBackend = BasicDispatcher>
364 class FunctorDispatcher
366 typedef LOKI_TYPELIST_2(BaseLhs &, BaseRhs &) ArgsList;
367 typedef Functor<ResultType, ArgsList, LOKI_DEFAULT_THREADING> FunctorType;
369 DispatcherBackend<BaseLhs, BaseRhs, ResultType, FunctorType> backEnd_;
372 template <class SomeLhs, class SomeRhs, class Fun>
373 void Add(const Fun &fun)
375 typedef Private::FunctorDispatcherHelper<
379 CastingPolicy<SomeLhs, BaseLhs>,
380 CastingPolicy<SomeRhs, BaseRhs>,
383 backEnd_.template Add<SomeLhs, SomeRhs>(FunctorType(Adapter(fun)));
385 template <class SomeLhs, class SomeRhs, bool symmetric, class Fun>
386 void Add(const Fun &fun)
388 Add<SomeLhs,SomeRhs>(fun);
392 // Note: symmetry only makes sense where BaseLhs==BaseRhs
393 typedef Private::FunctorDispatcherHelper<
397 CastingPolicy<SomeLhs, BaseLhs>,
398 CastingPolicy<SomeRhs, BaseLhs>,
401 backEnd_.template Add<SomeRhs, SomeLhs>(FunctorType(AdapterR(fun)));
405 template <class SomeLhs, class SomeRhs>
408 backEnd_.template Remove<SomeLhs, SomeRhs>();
411 ResultType Go(BaseLhs &lhs, BaseRhs &rhs)
413 return backEnd_.Go(lhs, rhs);
420 #endif // end file guardian