1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
#ifndef BOOST_PP_IS_ITERATING
# ifndef DISPATCHER_HPP_INCLUDED
# define DISPATCHER_HPP_INCLUDED
//do something 1 time (first include)
# include <boost/array.hpp>
# include <boost/bind.hpp>
# include <boost/function.hpp>
# include <boost/preprocessor/repetition.hpp>
# include <boost/preprocessor/arithmetic/add.hpp>
# include <boost/preprocessor/punctuation/comma_if.hpp>
# include <boost/preprocessor/iteration/iterate.hpp>
# include <typeinfo>
# include <map>
# ifndef DISPACHER_MAX_SIZE
# define DISPACHER_MAX_SIZE 5 // default maximum size is 5
# endif
//Special macro
#define MY_COUNT(z,n,macro) macro(BOOST_PP_ADD(n,1)) //internal use only (MY_ENUM)
#define MY_ENUM(n,macro) BOOST_PP_ENUM(n, MY_COUNT , macro) //call n times macro(i) with comma separator and i going from 1 to n
//default mapper
template< int, class dispatcher_type, class signature >
struct mapper
{};
template< int, class dispatcher_type, class signature >
class basic_dispatcher
{};
// generate specializations
# define BOOST_PP_ITERATION_LIMITS (1, DISPACHER_MAX_SIZE )
# define BOOST_PP_FILENAME_1 "dispatcher.hpp" // this file
# include BOOST_PP_ITERATE()
# endif // DISPATCHER_HPP_INCLUDED
#else // BOOST_PP_IS_ITERATING
#define n BOOST_PP_ITERATION()
#if n > 0
#define ENUM_TEMPLATE(n) class BOOST_PP_CAT(T,n) //class Tn
#define ENUM_ARGS(n) BOOST_PP_CAT(T , n) BOOST_PP_CAT(a , n) //T1 a1
#define ENUM_CAST(n) BOOST_PP_CAT(BOOST_PP_CAT(static_cast<ff::arg , n) , _type>) ( BOOST_PP_CAT(a , n) ) //static_cast<ff::arg1_type>(a1)
#define ENUM_BIND(n) BOOST_PP_CAT( BOOST_PP_CAT(ff::arg , n) ,_type ) //ff::arg1_type
#define ENUM_BIND_ARG(n) BOOST_PP_CAT(_ , n) //_1
#define ENUM_FUNCTION_ARGS(n) BOOST_PP_CAT(a,n) //a1
#define ENUM_BOOST_FUNCTION_ARGS(n) BOOST_PP_CAT(BOOST_PP_CAT(typename function_type::arg , n) , _type) BOOST_PP_CAT(a , n) //typename function_type::arg1_type a1
#define ENUM_BOOST_FUNCTION_TEMPLATE_ARGS(n) BOOST_PP_CAT(BOOST_PP_CAT(typename function_type::arg , n) , _type) //typename function_type::arg1_type
#define ENUM_TYPEID_TYPE(n) &typeid(BOOST_PP_CAT( BOOST_PP_CAT(ff::arg , n) ,_type )) //&typeid(ff::arg1_type)
#define ENUM_TYPEID_OBJECT(n) &typeid(BOOST_PP_CAT(a,n)) //&typeid(a1)
//template specialization of the basic dispatcher.
template< class dispatcher_type ,class signature_type>
class basic_dispatcher<n,dispatcher_type,signature_type>
{
public:
typedef typename boost::function<signature_type> function_type;
typedef typename function_type::result_type result_type;
virtual ~basic_dispatcher()
{}
template< class signature , class arg>
static void register_function( arg fun )
{
typedef typename boost::function<signature> ff;
boost::array<const std::type_info*,n> tmp = {MY_ENUM(n,ENUM_TYPEID_TYPE)};
functions()[ tmp ] = bindfun_<signature_type,signature>(ff(fun));
}
virtual result_type default_function(MY_ENUM(n,ENUM_BOOST_FUNCTION_ARGS)) = 0;
result_type operator()(MY_ENUM(n,ENUM_BOOST_FUNCTION_ARGS))
{
boost::array<const std::type_info*,n> tmp = {MY_ENUM(n,ENUM_TYPEID_OBJECT)};
std::map<boost::array<const std::type_info*,n>,function_type > & mymap = functions();
std::map<boost::array<const std::type_info*,n>,function_type >::iterator it = mymap.find(tmp);
if(it != mymap.end())
return it->second(MY_ENUM(n,ENUM_FUNCTION_ARGS));
else
return default_function(MY_ENUM(n,ENUM_FUNCTION_ARGS));
}
private:
//call a boost::function with n arguments, and cast them to match sign_from signature
template <class sign_from , MY_ENUM(n,ENUM_TEMPLATE)>
static typename boost::function<sign_from>::result_type call_ ( boost::function<sign_from > f , MY_ENUM(n,ENUM_ARGS) )
{
typedef boost::function<sign_from> ff;
return f( MY_ENUM(n,ENUM_CAST) );
}
//cast a function object with signature sign_from to a function of type sign_to
template< class sign_to,class sign_from>
static boost::function<sign_to> bindfun_ (boost::function<sign_from> f)
{
typedef boost::function<sign_to> ff;
return boost::function<sign_to>(boost::bind(call_ <sign_from , MY_ENUM(n,ENUM_BIND)>,f , MY_ENUM(n,ENUM_BIND_ARG) ));
}
static std::map< boost::array<const std::type_info*,n> , function_type > & functions()
{
static std::map< boost::array<const std::type_info*,n> , boost::function<signature_type> > static_map;
return static_map;
}
};
#undef ENUM_TEMPLATE
#undef ENUM_ARGS
#undef ENUM_CAST
#undef ENUM_BIND
#undef ENUM_BIND_ARG
#undef ENUM_FUNCTION_ARGS
#undef ENUM_BOOST_FUNCTION_ARGS
#undef ENUM_TYPEID_TYPE
#undef ENUM_TYPEID_OBJECT
#endif //n > 0
#undef n
#endif // BOOST_PP_IS_ITERATING |
Partager