322 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			322 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include <boost/preprocessor.hpp>
 | 
						|
 | 
						|
#define gettypeinfo(z,n,text)  ti.push_back(Get_Type_Info<Param ## n>::get());
 | 
						|
#define casthelper(z,n,text) ,dispatchkit::boxed_cast< Param ## n >(params[n])
 | 
						|
 | 
						|
 | 
						|
#ifndef  BOOST_PP_IS_ITERATING
 | 
						|
#ifndef __proxy_functions_hpp__
 | 
						|
#define __proxy_functions_hpp__
 | 
						|
 | 
						|
#include "boxed_value.hpp"
 | 
						|
#include "type_info.hpp"
 | 
						|
#include <string>
 | 
						|
#include <boost/function.hpp>
 | 
						|
#include <boost/bind.hpp>
 | 
						|
#include <boost/lexical_cast.hpp>
 | 
						|
 | 
						|
#include <stdexcept>
 | 
						|
#include <vector>
 | 
						|
 | 
						|
namespace dispatchkit
 | 
						|
{
 | 
						|
  // handle_return implementations
 | 
						|
  template<typename Ret>
 | 
						|
    struct Handle_Return
 | 
						|
    {
 | 
						|
      Boxed_Value operator()(const boost::function<Ret ()> &f)
 | 
						|
      {
 | 
						|
        return Boxed_Value(f());
 | 
						|
      }
 | 
						|
    };
 | 
						|
 | 
						|
  template<typename Ret>
 | 
						|
    struct Handle_Return<Ret &>
 | 
						|
    {
 | 
						|
      Boxed_Value operator()(const boost::function<Ret &()> &f)
 | 
						|
      {
 | 
						|
        return Boxed_Value(boost::ref(f()));
 | 
						|
      }
 | 
						|
    };
 | 
						|
 | 
						|
  template<>
 | 
						|
    struct Handle_Return<Boxed_Value>
 | 
						|
    {
 | 
						|
      Boxed_Value operator()(const boost::function<Boxed_Value ()> &f)
 | 
						|
      {
 | 
						|
        return f();
 | 
						|
      }
 | 
						|
    };
 | 
						|
 | 
						|
  template<>
 | 
						|
    struct Handle_Return<Boxed_Value &>
 | 
						|
    {
 | 
						|
      Boxed_Value operator()(const boost::function<Boxed_Value &()> &f)
 | 
						|
      {
 | 
						|
        return f();
 | 
						|
      }
 | 
						|
    };
 | 
						|
 | 
						|
  template<>
 | 
						|
    struct Handle_Return<void>
 | 
						|
    {
 | 
						|
      Boxed_Value operator()(const boost::function<void ()> &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<typename T>
 | 
						|
      Param_List_Builder &operator<<(T t)
 | 
						|
      {
 | 
						|
        objects.push_back(Boxed_Value(t));
 | 
						|
        return *this;
 | 
						|
      }
 | 
						|
 | 
						|
    operator const std::vector<Boxed_Value> &() const
 | 
						|
    {
 | 
						|
      return objects;
 | 
						|
    }
 | 
						|
 | 
						|
    std::vector<Boxed_Value> 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<Boxed_Value> ¶ms) = 0;
 | 
						|
      virtual std::vector<Type_Info> get_param_types() = 0;
 | 
						|
      virtual bool operator==(const Proxy_Function &) const = 0;
 | 
						|
  };
 | 
						|
 | 
						|
  class Dynamic_Proxy_Function : public Proxy_Function
 | 
						|
  {
 | 
						|
    public:
 | 
						|
      Dynamic_Proxy_Function(const boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> &t_f, int arity=-1)
 | 
						|
        : m_f(t_f), m_arity(arity)
 | 
						|
      {
 | 
						|
      }
 | 
						|
 | 
						|
      bool operator==(const Proxy_Function &f) const
 | 
						|
      {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      virtual ~Dynamic_Proxy_Function() {}
 | 
						|
 | 
						|
      virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
 | 
						|
      {
 | 
						|
        if (m_arity < 0 || params.size() == size_t(m_arity))
 | 
						|
        {
 | 
						|
          return m_f(params);
 | 
						|
        } else {
 | 
						|
          throw arity_error(params.size(), m_arity);
 | 
						|
        } 
 | 
						|
      }
 | 
						|
 | 
						|
      virtual std::vector<Type_Info> get_param_types()
 | 
						|
      {
 | 
						|
        return build_param_type_list(m_f);
 | 
						|
      }
 | 
						|
 | 
						|
    private:
 | 
						|
      boost::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
 | 
						|
      int m_arity;
 | 
						|
  };
 | 
						|
 | 
						|
  class Bound_Function : public Proxy_Function
 | 
						|
  {
 | 
						|
    public:
 | 
						|
      Bound_Function(const boost::shared_ptr<Proxy_Function> &t_f, 
 | 
						|
                     const std::vector<Boxed_Value> &t_args)
 | 
						|
        : m_f(t_f), m_args(t_args)
 | 
						|
      {
 | 
						|
      }
 | 
						|
 | 
						|
      bool operator==(const Proxy_Function &f) const
 | 
						|
      {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      virtual ~Bound_Function() {}
 | 
						|
 | 
						|
      virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
 | 
						|
      {
 | 
						|
        typedef std::vector<Boxed_Value>::const_iterator pitr;
 | 
						|
 | 
						|
        pitr parg = params.begin();
 | 
						|
        pitr barg = m_args.begin();
 | 
						|
 | 
						|
        std::vector<Boxed_Value> args;
 | 
						|
 | 
						|
        while (true)
 | 
						|
        {
 | 
						|
          while (barg != m_args.end() && !barg->is_unknown())
 | 
						|
          {
 | 
						|
            args.push_back(*barg);
 | 
						|
            ++barg;
 | 
						|
          }
 | 
						|
 | 
						|
          if (parg != params.end())
 | 
						|
          {
 | 
						|
            args.push_back(*parg);
 | 
						|
            ++parg;
 | 
						|
          }
 | 
						|
 | 
						|
          if (barg != m_args.end() && barg->is_unknown())
 | 
						|
          {
 | 
						|
            ++barg;
 | 
						|
          } 
 | 
						|
 | 
						|
          if (parg == params.end() && barg == m_args.end())
 | 
						|
          {
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        return (*m_f)(args);
 | 
						|
      }
 | 
						|
 | 
						|
      virtual std::vector<Type_Info> get_param_types()
 | 
						|
      {
 | 
						|
        return std::vector<Type_Info>();
 | 
						|
      }
 | 
						|
 | 
						|
    private:
 | 
						|
      boost::shared_ptr<Proxy_Function> m_f;
 | 
						|
      std::vector<Boxed_Value> m_args;
 | 
						|
  };
 | 
						|
 | 
						|
  template<typename Func>
 | 
						|
    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<const Proxy_Function_Impl<Func> &>(t_func);
 | 
						|
          return true; 
 | 
						|
        } catch (const std::bad_cast &) {
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 
 | 
						|
      virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
 | 
						|
      {
 | 
						|
        return call_func(m_f, params);
 | 
						|
      }
 | 
						|
 | 
						|
      virtual std::vector<Type_Info> get_param_types()
 | 
						|
      {
 | 
						|
        return build_param_type_list(m_f);
 | 
						|
      }
 | 
						|
 | 
						|
    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<std::pair<std::string, boost::shared_ptr<Proxy_Function> > > &funcs,
 | 
						|
      const std::vector<Boxed_Value> &plist)
 | 
						|
  {
 | 
						|
    for (std::vector<std::pair<std::string, boost::shared_ptr<Proxy_Function> > >::const_iterator itr = funcs.begin();
 | 
						|
        itr != funcs.end();
 | 
						|
        ++itr)
 | 
						|
    {
 | 
						|
      try {
 | 
						|
        return (*itr->second)(plist);
 | 
						|
      } catch (const bad_boxed_cast &) {
 | 
						|
        //try again
 | 
						|
      } catch (const arity_error &) {
 | 
						|
        //invalid num params, try again
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    throw dispatch_error();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
# endif
 | 
						|
#else
 | 
						|
# define n BOOST_PP_ITERATION()
 | 
						|
 | 
						|
namespace dispatchkit
 | 
						|
{
 | 
						|
 | 
						|
  template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
 | 
						|
    std::vector<Type_Info> build_param_type_list(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f)
 | 
						|
    {
 | 
						|
      std::vector<Type_Info> ti;
 | 
						|
      ti.push_back(Get_Type_Info<Ret>::get());
 | 
						|
 | 
						|
      BOOST_PP_REPEAT(n, gettypeinfo, ~)
 | 
						|
 | 
						|
      return ti;
 | 
						|
    }
 | 
						|
 | 
						|
  template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
 | 
						|
    Boxed_Value call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
 | 
						|
        const std::vector<Boxed_Value> ¶ms)
 | 
						|
    {
 | 
						|
      if (params.size() != n)
 | 
						|
      {
 | 
						|
        throw arity_error(params.size(), n);
 | 
						|
      } else {
 | 
						|
        return Handle_Return<Ret>()(boost::bind(f BOOST_PP_REPEAT(n, casthelper, ~)));
 | 
						|
      }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 |