Apply Index expansion technique to simplify code

Thanks @sean-parent I saw the technique in your future implementation
This commit is contained in:
Jason Turner
2015-06-01 09:43:29 -06:00
parent da8fa77558
commit 7026229273

View File

@@ -53,6 +53,23 @@ namespace chaiscript
{
namespace detail
{
template<size_t ... I>
struct Indexes
{
};
template<size_t S, size_t ... I>
struct Make_Indexes
{
typedef typename Make_Indexes<S-1, I..., sizeof...(I)>::indexes indexes;
};
template<size_t ... I>
struct Make_Indexes<0, I...>
{
typedef Indexes<I...> indexes;
};
/**
* Used by Proxy_Function_Impl to return a list of all param types
* it contains.
@@ -65,77 +82,39 @@ namespace chaiscript
}
// Forward declaration
template<typename ... Rest>
struct Try_Cast;
template<typename Param, typename ... Rest>
struct Try_Cast<Param, Rest...>
{
static void do_try(const std::vector<Boxed_Value> &params, size_t generation, const Type_Conversions &t_conversions)
{
boxed_cast<Param>(params[generation], &t_conversions);
Try_Cast<Rest...>::do_try(params, generation+1, t_conversions);
}
};
// 0th case
template<>
struct Try_Cast<>
{
static void do_try(const std::vector<Boxed_Value> &, size_t, const Type_Conversions &)
{
}
};
/**
* Used by Proxy_Function_Impl to determine if it is equivalent to another
* Proxy_Function_Impl object. This function is primarily used to prevent
* registration of two functions with the exact same signatures
*/
template<typename Ret, typename ... Params>
bool compare_types_cast(Ret (*)(Params...),
template<typename Ret, typename ... Params, size_t ... I>
bool compare_types_cast(Indexes<I...>, Ret (*)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
{
try {
Try_Cast<Params...>::do_try(params, 0, t_conversions);
std::initializer_list<void *>{(boxed_cast<Params>(params[I], &t_conversions), nullptr)...};
return true;
} catch (const exception::bad_boxed_cast &) {
return false;
}
return true;
}
template<typename Ret, int count, typename ... Params>
struct Call_Func
{
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{
return Call_Func<Ret, count - 1, Params...>::do_call(f, params, t_conversions, std::forward<InnerParams>(innerparams)..., params[sizeof...(Params) - count]);
}
};
template<typename Ret, typename ... Params>
struct Call_Func<Ret, 0, Params...>
bool compare_types_cast(Ret (*f)(Params...),
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
#ifdef CHAISCRIPT_MSVC
#pragma warning(push)
#pragma warning(disable : 4100) /// Disable unreferenced formal parameter warning, which only shows up in MSVC I don't think there's any way around it \todo evaluate this
#endif
template<typename ... InnerParams>
static Ret do_call(const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &, const Type_Conversions &t_conversions, InnerParams &&... innerparams)
{
return f(boxed_cast<Params>(std::forward<InnerParams>(innerparams), &t_conversions)...);
}
#ifdef CHAISCRIPT_MSVC
#pragma warning(pop)
#endif
};
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
return compare_types_cast(indexes(), f, params, t_conversions);
}
template<typename Ret, typename ... Params, size_t ... I>
Ret call_func(Indexes<I...>, const std::function<Ret (Params...)> &f,
const std::vector<Boxed_Value> &params, const Type_Conversions &t_conversions)
{
return f(boxed_cast<Params>(params[I], &t_conversions)...);
}
/**
* Used by Proxy_Function_Impl to perform typesafe execution of a function.
@@ -149,7 +128,8 @@ namespace chaiscript
{
if (params.size() == sizeof...(Params))
{
return Call_Func<Ret, sizeof...(Params), Params...>::do_call(f, params, t_conversions);
typedef typename Make_Indexes<sizeof...(Params)>::indexes indexes;
return call_func(indexes(), f, params, t_conversions);
}
throw exception::arity_error(static_cast<int>(params.size()), sizeof...(Params));