Created
March 3, 2011 11:03
-
-
Save einblicker/852624 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef STATIC_DISPATCHER_HPP_INCLUDED | |
#define STATIC_DISPATCHER_HPP_INCLUDED | |
#include <boost/mpl/list.hpp> | |
#include <boost/mpl/front.hpp> | |
#include <boost/mpl/pop_front.hpp> | |
#include <boost/mpl/index_of.hpp> | |
#include <boost/mpl/bool.hpp> | |
#include <boost/mpl/if.hpp> | |
#include <boost/mpl/replace.hpp> | |
#include <boost/mpl/push_front.hpp> | |
#include <boost/type_traits.hpp> | |
namespace dispatcher { | |
namespace detail { | |
template<class TL, class T> | |
struct most_derived_aux { | |
private: | |
typedef typename boost::mpl::front<TL>::type head; | |
typedef typename boost::mpl::pop_front<TL>::type tail; | |
typedef typename most_derived_aux<tail, T>::type candidate; | |
public: | |
typedef typename boost::mpl::if_c<boost::is_base_of<candidate, head>::value, head, candidate>::type type; | |
}; | |
template<class T> | |
struct most_derived_aux<boost::mpl::l_end, T> { | |
typedef T type; | |
}; | |
template<class TL> | |
struct most_derived { | |
private: | |
typedef typename boost::mpl::front<TL>::type head; | |
typedef typename boost::mpl::pop_front<TL>::type tail; | |
public: | |
typedef typename most_derived_aux<tail, head>::type type; | |
}; | |
template<class TL> | |
struct derived_to_front { | |
private: | |
typedef typename most_derived<TL>::type the_most_derived; | |
typedef typename boost::mpl::front<TL>::type head; | |
typedef typename boost::mpl::pop_front<TL>::type tail; | |
typedef typename boost::mpl::replace<tail, the_most_derived, head>::type L; | |
public: | |
typedef typename boost::mpl::push_front<L, the_most_derived>::type type; | |
}; | |
template<> | |
struct derived_to_front<boost::mpl::l_end> { | |
typedef boost::mpl::l_end type; | |
}; | |
template | |
< | |
class Executor, | |
template <class> class Caller, | |
class Base1, | |
class TL1, | |
bool symmetric, | |
class Base2, | |
class TL2, | |
class Result, | |
class TL1Org, | |
class TL2Org | |
> | |
struct static_dispatcher_aux | |
{ | |
private: | |
typedef typename boost::mpl::front<TL1>::type head; | |
typedef typename derived_to_front<typename boost::mpl::pop_front<TL1>::type>::type tail; | |
template<class Res> | |
struct invocation_traits { | |
template<class SomeLhs, class SomeRhs> | |
static Res do_dispatch(SomeLhs& lhs, SomeRhs& rhs, Executor& exec, boost::mpl::bool_<false>) { | |
return Caller<Res>::call(lhs, rhs, exec); | |
} | |
template<class SomeLhs, class SomeRhs> | |
static Res do_dispatch(SomeLhs& lhs, SomeRhs& rhs, Executor& exec, boost::mpl::bool_<true>) { | |
return Caller<Res>::call(rhs, lhs, exec); | |
} | |
}; | |
public: | |
static Result go(Base1& lhs, Base2& rhs, Executor& exec) { | |
if (head* p1 = dynamic_cast<head*>(&lhs)) { | |
return dispatch_rhs(*p1, rhs, exec); | |
} else { | |
return static_dispatcher_aux<Executor, Caller, Base1, tail, symmetric, Base2, TL2, Result, TL1Org, TL2Org>::go(lhs, rhs, exec); | |
} | |
} | |
private: | |
template<class SomeLhs> | |
static Result dispatch_rhs(SomeLhs& lhs, Base2& rhs, Executor& exec) { | |
typedef typename boost::mpl::front<TL2>::type head; | |
typedef typename derived_to_front<typename boost::mpl::pop_front<TL2>::type>::type tail; | |
if (head* p2 = dynamic_cast<head*>(&rhs)) { | |
typedef typename boost::mpl::index_of<TL1Org, SomeLhs>::type index1; | |
typedef typename boost::mpl::index_of<TL2Org, head>::type index2; | |
enum { swap = symmetric && index1::value < index2::value }; | |
typedef invocation_traits<Result> call_traits; | |
return call_traits::do_dispatch(lhs, *p2, exec, boost::mpl::bool_<swap>()); | |
} else { | |
return static_dispatcher_aux<Executor, Caller, Base1, TL1, symmetric, Base2, tail, Result, TL1Org, TL2Org>::dispatch_rhs(lhs, rhs, exec); | |
} | |
} | |
}; | |
template | |
< | |
class Executor, | |
template <class> class Caller, | |
class Base1, | |
class Base2, | |
bool symmetric, | |
class TL2, | |
class Result, | |
class TL1Org, | |
class TL2Org | |
> | |
struct static_dispatcher_aux<Executor, Caller, Base1, boost::mpl::l_end, symmetric, Base2, TL2, Result, TL1Org, TL2Org> | |
{ | |
static Result go(Base1& lhs, Base2& rhs, Executor& exec) { | |
return Caller<Result>::error(lhs, rhs, exec); | |
} | |
}; | |
template | |
< | |
class Executor, | |
template <class> class Caller, | |
class Base1, | |
class TL1, | |
bool symmetric, | |
class Base2, | |
class Result, | |
class TL1Org, | |
class TL2Org | |
> | |
struct static_dispatcher_aux<Executor, Caller, Base1, TL1, symmetric, Base2, boost::mpl::l_end, Result, TL1Org, TL2Org> | |
{ | |
static Result go(Base1& lhs, Base2& rhs, Executor& exec) { | |
return Caller<Result>::error(lhs, rhs, exec); | |
} | |
}; | |
} | |
template | |
< | |
class Executor, | |
template <class> class Caller, | |
class Base1, | |
class TL1, | |
bool symmetric = true, | |
class Base2 = Base1, | |
class TL2 = TL1, | |
class Result = void | |
> | |
struct static_dispatcher : | |
detail::static_dispatcher_aux<Executor, Caller, Base1, TL1, symmetric, Base2, TL2, Result, TL1, TL2> | |
{ | |
}; | |
} | |
#endif // STATIC_DISPATCHER_HPP_INCLUDED |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment