// This file is distributed under the BSD License. // See "license.txt" for details. // Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) // Copyright 2009-2014, Jason Turner (jason@emptycrate.com) // http://www.chaiscript.com #ifndef CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #define CHAISCRIPT_PROXY_FUNCTIONS_DETAIL_HPP_ #include "boxed_value.hpp" #include "boxed_cast.hpp" #include "type_info.hpp" #include "handle_return.hpp" #include #include #include namespace chaiscript { namespace exception { /** * Exception thrown when there is a mismatch in number of * parameters during Proxy_Function execution */ 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() CHAISCRIPT_NOEXCEPT {} int got; int expected; }; } namespace dispatch { namespace detail { template struct Build_Param_Type_List; template struct Build_Param_Type_List { static void build(std::vector &t_params) { t_params.push_back(chaiscript::detail::Get_Type_Info::get()); Build_Param_Type_List::build(t_params); } }; // 0th case template<> struct Build_Param_Type_List<> { static void build(std::vector &) { } }; /** * Used by Proxy_Function_Impl to return a list of all param types * it contains. */ template std::vector build_param_type_list(Ret (*)(Params...)) { /// \todo this code was previously using { chaiscript::detail::Get_Type_Info::get()... } /// but this seems to indicate another bug with MSVC's uniform initializer lists std::vector params; params.push_back(chaiscript::detail::Get_Type_Info::get()); Build_Param_Type_List::build(params); return params; } // Forward declaration template struct Try_Cast; template struct Try_Cast { static void do_try(const std::vector ¶ms, int generation, const Dynamic_Cast_Conversions &t_conversions) { boxed_cast(params[generation], &t_conversions); Try_Cast::do_try(params, generation+1, t_conversions); } }; // 0th case template<> struct Try_Cast<> { static void do_try(const std::vector &, int, const Dynamic_Cast_Conversions &) { } }; #ifdef BOOST_MSVC #pragma warning(pop) #endif /** * Used by Proxy_Function_Impl to determine if it is equivalent to another * Proxy_Function_Impl object. This function is primarly used to prevent * registration of two functions with the exact same signatures */ template bool compare_types_cast(Ret (*)(Params...), const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) { try { Try_Cast::do_try(params, 0, t_conversions); } catch (const exception::bad_boxed_cast &) { return false; } return true; } template struct Call_Func { template static Ret do_call(const std::function &f, const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) { return Call_Func::do_call(f, params, t_conversions, std::forward(innerparams)..., params[sizeof...(Params) - count]); } }; template struct Call_Func { template static Ret do_call(const std::function &f, const std::vector &, const Dynamic_Cast_Conversions &t_conversions, InnerParams &&... innerparams) { return f(boxed_cast(std::forward(innerparams), &t_conversions)...); } }; /** * Used by Proxy_Function_Impl to perform typesafe execution of a function. * The function attempts to unbox each paramter to the expected type. * if any unboxing fails the execution of the function fails and * the bad_boxed_cast is passed up to the caller. */ template Ret call_func(const std::function &f, const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) { if (params.size() == sizeof...(Params)) { return Call_Func::do_call(f, params, t_conversions); } throw exception::arity_error(static_cast(params.size()), sizeof...(Params)); } } } } namespace chaiscript { namespace dispatch { namespace detail { template struct Do_Call { template static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) { return Handle_Return::handle(call_func(fun, params, t_conversions)); } }; template<> struct Do_Call { template static Boxed_Value go(const std::function &fun, const std::vector ¶ms, const Dynamic_Cast_Conversions &t_conversions) { call_func(fun, params, t_conversions); return Handle_Return::handle(); } }; } } } #endif