#include #define gettypeinfo(z,n,text) ti.push_back(Get_Type_Info::get()); #define casthelper(z,n,text) ,dispatchkit::boxed_cast< Param ## n >(params[n]) #define comparetype(z,n,text) && ((Get_Type_Info::get() == params[n].get_type_info())) #define trycast(z,n,text) dispatchkit::boxed_cast(params[n]); #ifndef BOOST_PP_IS_ITERATING #ifndef __proxy_functions_hpp__ #define __proxy_functions_hpp__ #include "boxed_value.hpp" #include "type_info.hpp" #include #include #include #include #include #include namespace dispatchkit { // handle_return implementations template struct Handle_Return { Boxed_Value operator()(const boost::function &f) { return Boxed_Value(f()); } }; template struct Handle_Return { Boxed_Value operator()(const boost::function &f) { return Boxed_Value(boost::ref(f())); } }; template<> struct Handle_Return { Boxed_Value operator()(const boost::function &f) { return f(); } }; template<> struct Handle_Return { Boxed_Value operator()(const boost::function &f) { return f(); } }; template<> struct Handle_Return { Boxed_Value operator()(const boost::function &f) { f(); return Boxed_Value(Boxed_Value::Void_Type()); } }; struct Param_List_Builder { Param_List_Builder &operator<<(const Boxed_Value &so) { objects.push_back(so); return *this; } template Param_List_Builder &operator<<(T t) { objects.push_back(Boxed_Value(t)); return *this; } operator const std::vector &() const { return objects; } std::vector objects; }; struct arity_error : std::range_error { arity_error(int t_got, int t_expected) : std::range_error("Function dispatch arity mismatch"), got(t_got), expected(t_expected) { } virtual ~arity_error() throw() {} int got; int expected; }; } #define BOOST_PP_ITERATION_LIMITS ( 0, 10 ) #define BOOST_PP_FILENAME_1 "proxy_functions.hpp" #include BOOST_PP_ITERATE() namespace dispatchkit { class Proxy_Function { public: virtual ~Proxy_Function() {} virtual Boxed_Value operator()(const std::vector ¶ms) = 0; virtual std::vector get_param_types() const = 0; virtual bool operator==(const Proxy_Function &) const = 0; virtual bool types_match(const std::vector &types) const = 0; virtual std::string annotation() const = 0; }; class guard_error : public std::runtime_error { public: guard_error() throw() : std::runtime_error("Guard evaluation failed") { } virtual ~guard_error() throw() { } }; class Dynamic_Proxy_Function : public Proxy_Function { public: Dynamic_Proxy_Function( const boost::function &)> &t_f, int t_arity=-1, const std::string &t_description = "", const boost::shared_ptr &t_guard = boost::shared_ptr()) : m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard) { } virtual bool operator==(const Proxy_Function &) const { return false; } virtual bool types_match(const std::vector &types) const { return (m_arity < 0 || types.size() == size_t(m_arity)) && test_guard(types); } virtual ~Dynamic_Proxy_Function() {} virtual Boxed_Value operator()(const std::vector ¶ms) { if (m_arity < 0 || params.size() == size_t(m_arity)) { if (test_guard(params)) { return m_f(params); } else { throw guard_error(); } } else { throw arity_error(params.size(), m_arity); } } virtual std::vector get_param_types() const { std::vector types; types.push_back(Get_Type_Info::get()); if (m_arity >= 0) { for (int i = 0; i < m_arity; ++i) { types.push_back(Get_Type_Info::get()); } } else { types.push_back(Get_Type_Info >::get()); } return types; } virtual std::string annotation() const { return m_description; } private: bool test_guard(const std::vector ¶ms) const { if (m_guard) { try { return boxed_cast((*m_guard)(params)); } catch (const arity_error &) { return false; } catch (const bad_boxed_cast &) { return false; } } else { return true; } } boost::function &)> m_f; int m_arity; std::string m_description; boost::shared_ptr m_guard; }; struct Placeholder_Object { }; class Bound_Function : public Proxy_Function { public: Bound_Function(const boost::shared_ptr &t_f, const std::vector &t_args) : m_f(t_f), m_args(t_args) { } virtual bool operator==(const Proxy_Function &) const { return false; } virtual ~Bound_Function() {} virtual bool types_match(const std::vector &types) const { std::vector params = build_param_list(types); return m_f->types_match(params); } virtual Boxed_Value operator()(const std::vector ¶ms) { return (*m_f)(build_param_list(params)); } std::vector build_param_list(const std::vector ¶ms) const { typedef std::vector::const_iterator pitr; pitr parg = params.begin(); pitr barg = m_args.begin(); std::vector args; while (true) { while (barg != m_args.end() && !(barg->get_type_info() == Get_Type_Info::get())) { args.push_back(*barg); ++barg; } if (parg != params.end()) { args.push_back(*parg); ++parg; } if (barg != m_args.end() && barg->get_type_info() == Get_Type_Info::get()) { ++barg; } if (parg == params.end() && barg == m_args.end()) { break; } } return args; } virtual std::vector get_param_types() const { return std::vector(); } virtual std::string annotation() const { return ""; } private: boost::shared_ptr m_f; std::vector m_args; }; template class Proxy_Function_Impl : public Proxy_Function { public: Proxy_Function_Impl(const Func &f) : m_f(f) { } virtual ~Proxy_Function_Impl() {} virtual bool operator==(const Proxy_Function &t_func) const { try { dynamic_cast &>(t_func); return true; } catch (const std::bad_cast &) { return false; } } virtual Boxed_Value operator()(const std::vector ¶ms) { return call_func(m_f, params); } virtual std::vector get_param_types() const { return build_param_type_list(m_f); } virtual bool types_match(const std::vector &types) const { return compare_types(m_f, types); } virtual std::string annotation() const { return ""; } private: Func m_f; }; struct dispatch_error : std::runtime_error { dispatch_error() throw() : std::runtime_error("No matching function to dispatch to") { } virtual ~dispatch_error() throw() {} }; Boxed_Value dispatch(const std::vector > > &funcs, const std::vector &plist) { for (std::vector > >::const_iterator itr = funcs.begin(); itr != funcs.end(); ++itr) { try { return (*itr->second)(plist); } catch (const bad_boxed_cast &) { //parameter failed to cast, try again } catch (const arity_error &) { //invalid num params, try again } catch (const guard_error &) { //guard failed to allow the function to execute, //try again } } throw dispatch_error(); } } # endif #else # define n BOOST_PP_ITERATION() namespace dispatchkit { template std::vector build_param_type_list(const boost::function &) { std::vector ti; ti.push_back(Get_Type_Info::get()); BOOST_PP_REPEAT(n, gettypeinfo, ~) return ti; } template Boxed_Value call_func(const boost::function &f, const std::vector ¶ms) { if (params.size() != n) { throw arity_error(params.size(), n); } else { return Handle_Return()(boost::bind(f BOOST_PP_REPEAT(n, casthelper, ~))); } } template bool compare_types(const boost::function &, const std::vector ¶ms) { if (params.size() != n) { return false; } else { bool val = true BOOST_PP_REPEAT(n, comparetype, ~); if (val) return true; try { BOOST_PP_REPEAT(n, trycast, ~); } catch (const bad_boxed_cast &) { return false; } return true; } } } #endif