Skip to content

Instantly share code, notes, and snippets.

@einblicker
Created March 3, 2011 11:03
Show Gist options
  • Save einblicker/852624 to your computer and use it in GitHub Desktop.
Save einblicker/852624 to your computer and use it in GitHub Desktop.
#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