Ensure argument transparency.

This commit is contained in:
ThePhD 2016-04-18 08:27:30 -04:00
parent 062d2281d5
commit 96da27d565
5 changed files with 30 additions and 11 deletions

View File

@ -76,18 +76,18 @@ inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 1) {
template <bool checkargs = default_check_arguments, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>> template <bool checkargs = default_check_arguments, std::size_t... I, typename R, typename... Args, typename Fx, typename... FxArgs, typename = std::enable_if_t<!std::is_void<R>::value>>
inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
typedef meta::index_in_pack<this_state, Args...> state_pack_index; typedef meta::index_in_pack<this_state, Args...> state_index;
typedef std::integral_constant<int, state_pack_index::value == -1 ? INT_MAX : static_cast<int>(state_pack_index::value)> state_idx; typedef meta::index_in_pack<variadic_args, Args...> va_pack_index;
check_types<checkargs>{}.check(ta, tai, L, start, type_panic); check_types<checkargs>{}.check(ta, tai, L, start, type_panic);
return fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + (state_idx::value < I ? I - 1 : I))...); return fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I - static_cast<int>(state_index::value < I) - static_cast<int>(va_pack_index::value < I))...);
} }
template <bool checkargs = default_check_arguments, std::size_t... I, typename... Args, typename Fx, typename... FxArgs> template <bool checkargs = default_check_arguments, std::size_t... I, typename... Args, typename Fx, typename... FxArgs>
inline void call(types<void>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { inline void call(types<void>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
typedef meta::index_in_pack<this_state, Args...> state_pack_index; typedef meta::index_in_pack<this_state, Args...> state_index;
typedef std::integral_constant<int, state_pack_index::value == -1 ? INT_MAX : static_cast<int>(state_pack_index::value)> state_idx; typedef meta::index_in_pack<variadic_args, Args...> va_pack_index;
check_types<checkargs>{}.check(ta, tai, L, start, type_panic); check_types<checkargs>{}.check(ta, tai, L, start, type_panic);
fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + (state_idx::value < I ? I - 1 : I))...); fx(std::forward<FxArgs>(args)..., stack_detail::unchecked_get<Args>(L, start + I - static_cast<int>(state_index::value < I) - static_cast<int>(va_pack_index::value < I))...);
} }
} // stack_detail } // stack_detail

View File

@ -61,11 +61,11 @@ struct basic_check {
template <bool b> template <bool b>
struct check_types { struct check_types {
template <std::size_t I0, std::size_t... I, typename Arg0, typename... Args, typename Handler> template <std::size_t I0, std::size_t... I, typename T, typename... Args, typename Handler>
static bool check(types<Arg0, Args...>, std::index_sequence<I0, I...>, lua_State* L, int firstargument, Handler&& handler) { static bool check(types<T, Args...>, std::index_sequence<I0, I...>, lua_State* L, int firstargument, Handler&& handler) {
if (!stack::check<Arg0>(L, firstargument + I0, handler)) if (!stack::check<T>(L, firstargument + I0, handler))
return false; return false;
return check(types<Args...>(), std::index_sequence<I...>(), L, firstargument - static_cast<int>(std::is_same<this_state, meta::Unqualified<Arg0>>::value), std::forward<Handler>(handler)); return check(types<Args...>(), std::index_sequence<I...>(), L, firstargument - static_cast<int>(is_transparent_argument<meta::Unqualified<T>>::value), std::forward<Handler>(handler));
} }
template <typename Handler> template <typename Handler>

View File

@ -134,7 +134,7 @@ struct find_in_pack_v<V, Vs1, Vs...> : Or<Bool<(V::value == Vs1::value)>, find_i
namespace meta_detail { namespace meta_detail {
template<std::size_t I, typename T, typename... Args> template<std::size_t I, typename T, typename... Args>
struct index_in_pack : std::integral_constant<std::ptrdiff_t, -1> { }; struct index_in_pack : std::integral_constant<std::size_t, SIZE_MAX> { };
template<std::size_t I, typename T, typename T1, typename... Args> template<std::size_t I, typename T, typename T1, typename... Args>
struct index_in_pack<I, T, T1, Args...> : std::conditional_t<std::is_same<T, T1>::value, std::integral_constant<std::ptrdiff_t, I>, index_in_pack<I + 1, T, Args...>> { }; struct index_in_pack<I, T, T1, Args...> : std::conditional_t<std::is_same<T, T1>::value, std::integral_constant<std::ptrdiff_t, I>, index_in_pack<I + 1, T, Args...>> { };

View File

@ -315,6 +315,8 @@ using lightuserdata = basic_lightuserdata<reference>;
using stack_lightuserdata = basic_lightuserdata<stack_reference>; using stack_lightuserdata = basic_lightuserdata<stack_reference>;
class coroutine; class coroutine;
class thread; class thread;
struct variadic_args;
struct this_state;
template <typename T, typename = void> template <typename T, typename = void>
struct lua_type_of : std::integral_constant<type, type::userdata> {}; struct lua_type_of : std::integral_constant<type, type::userdata> {};
@ -434,6 +436,15 @@ struct is_proxy_primitive : is_lua_primitive<T> { };
template <typename T> template <typename T>
struct is_unique_usertype : std::false_type {}; struct is_unique_usertype : std::false_type {};
template <typename T>
struct is_transparent_argument : std::false_type {};
template <>
struct is_transparent_argument<this_state> : std::true_type {};
template <>
struct is_transparent_argument<variadic_args> : std::true_type {};
template<typename T> template<typename T>
inline type type_of() { inline type type_of() {
return lua_type_of<meta::Unqualified<T>>::value; return lua_type_of<meta::Unqualified<T>>::value;

View File

@ -781,3 +781,11 @@ TEST_CASE("functions/variadic_args", "Check to see we can receive multiple argum
REQUIRE(lx2.b); REQUIRE(lx2.b);
REQUIRE_FALSE(lx3.b); REQUIRE_FALSE(lx3.b);
} }
TEST_CASE("functions/required_and_variadic_args", "Check if a certain number of arguments can still be required even when using variadic_args") {
sol::state lua;
lua.set_function("v", [](sol::this_state, sol::variadic_args, int, int) {});
REQUIRE_NOTHROW(lua.script("v(20, 25, 30)"));
REQUIRE_NOTHROW(lua.script("v(20, 25)"));
REQUIRE_THROWS(lua.script("v(20)"));
}