This mega-commit implements the new usertype_metatable while keeping everything else still intact. Blurgh, managing API versions suck...

This commit is contained in:
ThePhD 2016-06-03 21:40:23 -04:00
parent 9b65fb9f93
commit e35fe6be85
32 changed files with 1481 additions and 355 deletions

@ -1 +1 @@
Subproject commit e62740b328e100ac76821e151cb3cfe7412bd98a
Subproject commit f11b4f00eb029862dd2a4d7e3497324aba8a020f

218
sol/bind_traits.hpp Normal file
View File

@ -0,0 +1,218 @@
#pragma once
#include "tuple.hpp"
namespace sol {
namespace meta {
namespace meta_detail {
template<class F>
struct check_deducible_signature {
struct nat {};
template<class G>
static auto test(int) -> decltype(&G::operator(), void());
template<class>
static auto test(...) -> nat;
using type = std::is_void<decltype(test<F>(0))>;
};
} // meta_detail
template<class F>
struct has_deducible_signature : meta_detail::check_deducible_signature<F>::type { };
namespace meta_detail {
template <std::size_t I, typename T>
struct void_tuple_element : meta::tuple_element<I, T> {};
template <std::size_t I>
struct void_tuple_element<I, std::tuple<>> { typedef void type; };
template <std::size_t I, typename T>
using void_tuple_element_t = typename void_tuple_element<I, T>::type;
template <bool has_c_variadic, typename T, typename R, typename... Args>
struct basic_traits {
private:
typedef std::conditional_t<std::is_void<T>::value, int, T>& first_type;
public:
static const bool is_member_function = std::is_void<T>::value;
static const bool has_c_var_arg = has_c_variadic;
static const std::size_t arity = sizeof...(Args);
static const std::size_t free_arity = sizeof...(Args) + static_cast<std::size_t>(!std::is_void<T>::value);
typedef types<Args...> args_list;
typedef std::tuple<Args...> args_tuple;
typedef T object_type;
typedef R return_type;
typedef tuple_types<R> returns_list;
typedef R(function_type)(Args...);
typedef std::conditional_t<std::is_void<T>::value, args_list, types<first_type, Args...>> free_args_list;
typedef std::conditional_t<std::is_void<T>::value, R(Args...), R(first_type, Args...)> free_function_type;
typedef std::conditional_t<std::is_void<T>::value, R(*)(Args...), R(*)(first_type, Args...)> free_function_pointer_type;
typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
template<std::size_t i>
using arg_at = void_tuple_element_t<i, args_tuple>;
};
template<typename Signature, bool b = has_deducible_signature<Signature>::value>
struct fx_traits : basic_traits<false, void, void> {};
// Free Functions
template<typename R, typename... Args>
struct fx_traits<R(Args...), false> : basic_traits<false, void, R, Args...> {
typedef R(*function_pointer_type)(Args...);
};
template<typename R, typename... Args>
struct fx_traits<R(*)(Args...), false> : basic_traits<false, void, R, Args...> {
typedef R(*function_pointer_type)(Args...);
};
template<typename R, typename... Args>
struct fx_traits<R(Args..., ...), false> : basic_traits<true, void, R, Args...> {
typedef R(*function_pointer_type)(Args..., ...);
};
template<typename R, typename... Args>
struct fx_traits<R(*)(Args..., ...), false> : basic_traits<true, void, R, Args...> {
typedef R(*function_pointer_type)(Args..., ...);
};
// Member Functions
/* C-Style Variadics */
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...), false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...);
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...), false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...);
};
/* Const Volatile */
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const volatile, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const volatile;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const volatile, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const volatile;
};
/* Member Function Qualifiers */
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) &, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) &;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) &, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) &;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const &, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const &;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const &, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const &;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const volatile &, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const volatile &;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const volatile &, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const volatile &;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) &&, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) &&;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) &&, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) &&;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const &&, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const &&;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const &&, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const &&;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const volatile &&, false> : basic_traits<false, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args...) const volatile &&;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args..., ...) const volatile &&, false> : basic_traits<true, T, R, Args...> {
typedef R(T::* function_pointer_type)(Args..., ...) const volatile &&;
};
template<typename Signature>
struct fx_traits<Signature, true> : fx_traits<typename fx_traits<decltype(&Signature::operator())>::function_type, false> {};
template<typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
struct callable_traits : fx_traits<std::decay_t<Signature>> {
};
template<typename R, typename T>
struct callable_traits<R(T::*), true> {
typedef R Arg;
typedef T object_type;
using signature_type = R(T::*);
static const bool is_member_function = false;
static const std::size_t arity = 1;
static const std::size_t free_arity = 2;
typedef std::tuple<Arg> args_tuple;
typedef R return_type;
typedef types<Arg> args_list;
typedef meta::tuple_types<R> returns_list;
typedef R(function_type)(T&, R);
typedef R(*function_pointer_type)(T&, R);
typedef R(*free_function_pointer_type)(T&, R);
template<std::size_t i>
using arg_at = void_tuple_element_t<i, args_tuple>;
};
} // meta_detail
template<typename Signature>
struct bind_traits : meta_detail::callable_traits<Signature> {};
template<typename Signature>
using function_args_t = typename bind_traits<Signature>::args_list;
template<typename Signature>
using function_signature_t = typename bind_traits<Signature>::signature_type;
template<typename Signature>
using function_return_t = typename bind_traits<Signature>::return_type;
} // meta
} // sol

282
sol/call.hpp Normal file
View File

@ -0,0 +1,282 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rappt1101010z, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_CALL_HPP
#define SOL_CALL_HPP
#include "wrapper.hpp"
#include "property.hpp"
#include "stack.hpp"
namespace sol {
namespace call_detail {
template <bool b, typename F>
inline decltype(auto) pick(std::integral_constant<bool, b>, F&& f) {
return std::forward<F>(f);
}
template <typename R, typename W>
inline auto& pick(std::true_type, property_wrapper<R, W>& f) {
return f.read;
}
template <typename R, typename W>
inline auto& pick(std::false_type, property_wrapper<R, W>& f) {
return f.write;
}
namespace overload_detail {
template <std::size_t... M, typename Match, typename... Args>
inline int overload_match_arity(sol::types<>, std::index_sequence<>, std::index_sequence<M...>, Match&&, lua_State* L, int, int, Args&&...) {
return luaL_error(L, "sol: no matching function call takes this number of arguments and the specified types");
}
template <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::size_t... M, typename Match, typename... Args>
inline int overload_match_arity(sol::types<Fx, Fxs...>, std::index_sequence<I, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
typedef lua_bind_traits<meta::unqualified_t<Fx>> traits;
typedef meta::tuple_types<typename traits::return_type> return_types;
typedef typename traits::free_args_list args_list;
typedef typename args_list::indices args_indices;
int farity = traits::free_arity;
// compile-time eliminate any functions that we know ahead of time are of improper arity
if (meta::find_in_pack_v<index_value<traits::free_arity>, index_value<M>...>::value) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (traits::free_arity != fxarity) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::arity, M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
if (!stack::stack_detail::check_types<true>().check(args_list(), args_indices(), L, start, no_panic)) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
}
} // overload_detail
template <typename... Functions, typename Match, typename... Args>
inline int overload_match_arity(Match&& matchfx, lua_State* L, int fxarity, int start, Args&&... args) {
return overload_detail::overload_match_arity(types<Functions...>(), std::make_index_sequence<sizeof...(Functions)>(), std::index_sequence<>(), std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
template <typename... Functions, typename Match, typename... Args>
inline int overload_match(Match&& matchfx, lua_State* L, int start, Args&&... args) {
int fxarity = lua_gettop(L) - (start - 1);
return overload_match_arity<Functions...>(std::forward<Match>(matchfx), L, fxarity, start, std::forward<Args>(args)...);
}
template <typename F, bool is_index, bool is_variable, typename = void>
struct agnostic_lua_call_wrapper {
static int var_call(std::true_type, lua_State* L, F f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::free_args_list args_list;
return stack::call_into_lua<is_index ? 1 : 2>(returns_list(), args_list(), L, is_index ? 2 : 3, wrap::caller(), f);
}
static int var_call(std::false_type, lua_State* L, F f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::free_args_list args_list;
typedef typename wrap::returns_list returns_list;
return stack::call_into_lua(returns_list(), args_list(), L, 1, wrap::caller(), f);
}
static int call(lua_State* L, F f) {
return var_call(std::integral_constant<bool, is_variable>(), L, f);
}
};
template <typename F, bool is_index, bool is_variable>
struct agnostic_lua_call_wrapper<F, is_index, is_variable, std::enable_if_t<std::is_member_function_pointer<F>::value>> {
static int call(lua_State* L, F f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::returns_list returns_list;
typedef typename wrap::args_list args_list;
#ifdef SOL_SAFE_USERTYPE
typedef typename wrap::object_type object_type;
object_type* o = stack::get<object_type*>(L, 1);
if (o == nullptr) {
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions, make sure member variables are preceeded by the actual object with '.' syntax)");
}
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, wrap::caller(), f, *o);
#else
object_type& o = stack::get<object_type&>(L, 1);
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), args_list(), L, is_variable ? 3 : 2, wrap::caller(), f);
#endif // Safety
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<no_prop, is_index, is_variable, C> {
static int call(lua_State* L, no_prop) {
return luaL_error(L, is_index ? "sol: cannot read from a writeonly property" : "sol: cannot write to a readonly property");
}
};
template <typename F, bool is_variable>
struct agnostic_lua_call_wrapper<F, false, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef sol::lua_bind_traits<F> traits_type;
static int call_assign(std::true_type, lua_State* L, F f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::args_list args_list;
typedef typename wrap::object_type object_type;
#ifdef SOL_SAFE_USERTYPE
object_type* o = stack::get<object_type*>(L, 1);
if (o == nullptr) {
if (is_variable) {
return luaL_error(L, "sol: received null for 'self' argument (bad '.' access?)");
}
return luaL_error(L, "sol: received null for 'self' argument (pass 'self' as first argument)");
}
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, wrap::caller(), f, *o);
#else
object_type& o = stack::get<object_type&>(L, 1);
return stack::call_into_lua<is_variable ? 2 : 1>(types<void>(), args_list(), L, is_variable ? 3 : 2, wrap::caller(), f, o);
#endif // Safety
}
static int call_assign(std::false_type, lua_State* L, F f) {
return luaL_error(L, "sol: cannot write to this variable: copy assignment/constructor not available");
}
static int call_const(std::false_type, lua_State* L, F f) {
typedef typename traits_type::return_type R;
return call_assign(std::is_assignable<std::add_lvalue_reference_t<meta::unqualified_t<R>>, R>(), L, f);
}
static int call_const(std::true_type, lua_State* L, F f) {
return luaL_error(L, "sol: cannot write to a readonly (const) variable");
}
static int call(lua_State* L, F f) {
return call_const(std::is_const<typename traits_type::return_type>(), L, f);
}
};
template <typename F, bool is_variable>
struct agnostic_lua_call_wrapper<F, true, is_variable, std::enable_if_t<std::is_member_object_pointer<F>::value>> {
typedef sol::lua_bind_traits<F> traits_type;
static int call(lua_State* L, F f) {
typedef wrapper<meta::unqualified_t<F>> wrap;
typedef typename wrap::object_type object_type;
typedef typename wrap::returns_list returns_list;
#ifdef SOL_SAFE_USERTYPE
object_type* o = stack::get<object_type*>(L, 1);
if (o == nullptr) {
if (is_variable) {
return luaL_error(L, "sol: 'self' argument is nullptr (bad '.' access?)");
}
return luaL_error(L, "sol: 'self' argument is nullptr (pass 'self' as first argument)");
}
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, wrap::caller(), f, *o);
#else
object_type& o = stack::get<object_type&>(L, 1);
return stack::call_into_lua<is_variable ? 2 : 1>(returns_list(), types<>(), L, is_variable ? 3 : 2, wrap::caller(), f, o);
#endif // Safety
}
};
template <typename... Fs, bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<sol::overload_set<Fs...>, is_index, is_variable, C> {
typedef sol::overload_set<Fs...> F;
template <typename Fx, std::size_t I, typename... R, typename... Args>
static int select_call(sol::types<Fx>, sol::index_value<I>, sol::types<R...> r, sol::types<Args...> a, lua_State* L, int, int start, F& fx) {
auto& f = std::get<I>(fx.set);
return agnostic_lua_call_wrapper<Fx, is_index, is_variable>{}.call(L, f);
}
static int call(lua_State* L, F& fx) {
auto mfx = [&](auto&&... args) { return select_call(std::forward<decltype(args)>(args)...); };
return overload_match_arity<Fs...>(mfx, L, lua_gettop(L), 1, fx);
}
};
template <bool is_index, bool is_variable, typename C>
struct agnostic_lua_call_wrapper<sol::no_construction, is_index, is_variable, C> {
static int call(lua_State* L, sol::no_construction&) {
return luaL_error(L, "cannot call something tagged with 'no construction'");
}
};
template <typename T, typename F, bool is_index, bool is_variable, typename = void>
struct lua_call_wrapper : agnostic_lua_call_wrapper<F, is_index, is_variable> {};
template <typename T, typename... Args, bool is_index, bool is_variable, typename C>
struct lua_call_wrapper<T, sol::constructor_list<Args...>, is_index, is_variable, C> {
typedef sol::constructor_list<Args...> F;
static int call(lua_State* L, F&) {
static const auto& meta = usertype_traits<T>::metatable;
int argcount = lua_gettop(L);
call_syntax syntax = argcount > 0 ? stack::get_call_syntax(L, meta, 1) : call_syntax::dot;
argcount -= static_cast<int>(syntax);
T** pointerpointer = reinterpret_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
T*& referencepointer = *pointerpointer;
T* obj = reinterpret_cast<T*>(pointerpointer + 1);
referencepointer = obj;
reference userdataref(L, -1);
userdataref.pop();
function_detail::construct<T, Args...>(detail::constructor_match<T>(obj), L, argcount, 1 + static_cast<int>(syntax));
userdataref.push();
luaL_getmetatable(L, &meta[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 1);
return luaL_error(L, "sol: unable to get usertype metatable");
}
lua_setmetatable(L, -2);
return 1;
}
};
template <typename T, bool is_index, bool is_variable, typename Fx>
int call_wrapped(lua_State* L, Fx&& fx) {
return lua_call_wrapper<T, meta::unqualified_t<Fx>, is_index, is_variable>{}.call(L, std::forward<Fx>(fx));
}
template <typename T, typename = void>
struct is_var_bind : std::false_type {};
template <typename T>
struct is_var_bind<T, std::enable_if_t<std::is_member_object_pointer<T>::value>> : std::true_type {};
template <>
struct is_var_bind<no_prop> : std::true_type {};
template <typename R, typename W>
struct is_var_bind<property_wrapper<R, W>> : std::true_type {};
} // call_detail
template <typename T>
struct is_variable_binding : call_detail::is_var_bind<meta::unqualified_t<T>> {};
template <typename T>
struct is_function_binding : meta::neg<is_variable_binding<T>> {};
} // sol
#endif // SOL_CALL_HPP

View File

@ -59,7 +59,7 @@ private:
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n) {
int stacksize = lua_gettop( lua_state() );
int firstreturn = std::max( 1, stacksize - static_cast<int>( n ) );
int firstreturn = (std::max)( 1, stacksize - static_cast<int>( n ) );
luacall(n, LUA_MULTRET);
int poststacksize = lua_gettop(lua_state());
int returncount = poststacksize - (firstreturn - 1);

View File

@ -57,7 +57,7 @@ private:
function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n ) const {
int stacksize = lua_gettop( base_t::lua_state( ) );
int firstreturn = std::max( 1, stacksize - static_cast<int>( n ) );
int firstreturn = (std::max)( 1, stacksize - static_cast<int>( n ) );
luacall(n, LUA_MULTRET);
int poststacksize = lua_gettop( base_t::lua_state( ) );
int returncount = poststacksize - (firstreturn - 1);
@ -70,7 +70,7 @@ public:
basic_function& operator=(const basic_function&) = default;
basic_function(basic_function&&) = default;
basic_function& operator=(basic_function&&) = default;
basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
basic_function(const stack_reference& r) : basic_function(r.lua_state(), r.stack_index()) {}
basic_function(stack_reference&& r) : basic_function(r.lua_state(), r.stack_index()) {}
basic_function(lua_State* L, int index = -1): base_t(L, index) {
#ifdef SOL_CHECK_ARGUMENTS
@ -100,7 +100,7 @@ namespace stack {
template<typename Signature>
struct getter<std::function<Signature>> {
typedef meta::bind_traits<Signature> fx_t;
typedef typename fx_t::args_type args_types;
typedef typename fx_t::args_list args_lists;
typedef meta::tuple_types<typename fx_t::return_type> return_types;
template<typename... Args, typename... Ret>
@ -127,7 +127,7 @@ struct getter<std::function<Signature>> {
}
static std::function<Signature> get(lua_State* L, int index) {
return get_std_func(return_types(), args_types(), L, index);
return get_std_func(return_types(), args_lists(), L, index);
}
};
} // stack

View File

@ -31,6 +31,7 @@
#include "function_types_overload.hpp"
#include "function_types_allocator.hpp"
#include "resolve.hpp"
#include "call.hpp"
namespace sol {
template <typename Sig, typename... Ps>
@ -45,13 +46,6 @@ function_arguments<Sig, Args...> function_args( Args&&... args ) {
return function_arguments<Sig, Args...>(std::forward<Args>(args)...);
}
// Allow someone to make a member variable readonly (const)
template <typename R, typename T>
auto readonly( R T::* v ) {
typedef const R C;
return static_cast<C T::*>( v );
}
namespace stack {
template<typename... Sigs>
struct pusher<function_sig<Sigs...>> {

View File

@ -34,7 +34,7 @@ struct upvalue_free_function {
static int real_call(lua_State* L) {
auto udata = stack::stack_detail::get_as_upvalues<function_type*>(L);
function_type* fx = udata.first;
int r = stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), L, 1, fx);
int r = stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx);
return r;
}
@ -65,7 +65,7 @@ struct upvalue_member_function {
auto fx = [&item, &memfx](auto&&... args) -> typename traits_type::return_type {
return (item.*memfx)(std::forward<decltype(args)>(args)...);
};
return stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), L, 1, fx);
return stack::call_into_lua(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 1, fx);
}
static int call (lua_State* L) {
@ -151,7 +151,7 @@ struct upvalue_this_member_function {
auto& item = stack::get<T>(L, 1);
return (item.*memfx)(std::forward<decltype(args)>(args)...);
};
int n = stack::call_into_lua<1>(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_type(), L, 2, fx);
int n = stack::call_into_lua<1>(meta::tuple_types<typename traits_type::return_type>(), typename traits_type::args_list(), L, 2, fx);
return n;
}

View File

@ -23,9 +23,13 @@
#define SOL_FUNCTION_TYPES_CORE_HPP
#include "stack.hpp"
#include "wrapper.hpp"
#include <memory>
namespace sol {
namespace detail {
struct empty {};
}
template <typename RSig = void, typename WSig = void>
struct member_property {
typedef std::conditional_t<std::is_void<RSig>::value, detail::empty, RSig> R;
@ -150,7 +154,7 @@ inline decltype(auto) cleanup_key() {
template<typename T, typename Func, typename = void>
struct functor {
typedef meta::bind_traits<Func> traits_type;
typedef typename traits_type::args_type args_type;
typedef typename traits_type::args_list args_list;
typedef typename traits_type::return_type return_type;
typedef std::conditional_t<std::is_pointer<Func>::value || std::is_class<Func>::value, Func, std::add_pointer_t<Func>> function_type;
static const std::size_t arity = traits_type::arity;
@ -179,7 +183,7 @@ struct functor {
template<typename T, typename Func>
struct functor<T, Func, std::enable_if_t<!std::is_member_pointer<Func>::value && std::is_base_of<T, meta::unqualified_t<typename meta::bind_traits<Func>::template arg_at<0>>>::value>> {
typedef meta::bind_traits<Func> traits_type;
typedef meta::pop_front_type_t<typename traits_type::args_type> args_type;
typedef meta::pop_front_type_t<typename traits_type::args_list> args_list;
typedef typename traits_type::return_type return_type;
typedef std::conditional_t<std::is_pointer<Func>::value || std::is_class<Func>::value, Func, std::add_pointer_t<Func>> function_type;
static const std::size_t arity = traits_type::arity - 1;
@ -211,7 +215,7 @@ struct functor<T, Func, std::enable_if_t<!std::is_member_pointer<Func>::value &&
template<typename T, typename RSig, typename WSig, typename C>
struct functor<T, member_property<RSig, WSig>, C> {
typedef meta::bind_traits<std::conditional_t<std::is_void<WSig>::value, RSig, WSig>> traits_type;
typedef meta::pop_front_type_t<typename traits_type::args_type> args_type;
typedef meta::pop_front_type_t<typename traits_type::args_list> args_list;
typedef std::conditional_t<std::is_void<typename traits_type::return_type>::value, typename traits_type::template arg_at<0>, typename traits_type::return_type> return_type;
typedef member_property<RSig, WSig> function_type;
typedef meta::neg<std::is_void<RSig>> can_read;
@ -244,7 +248,7 @@ struct functor<T, member_property<RSig, WSig>, C> {
template<typename T, typename Func>
struct functor<T, Func, std::enable_if_t<std::is_member_object_pointer<Func>::value>> {
typedef meta::bind_traits<Func> traits_type;
typedef typename traits_type::args_type args_type;
typedef typename traits_type::args_list args_list;
typedef typename traits_type::return_type return_type;
static const std::size_t arity = traits_type::arity;
typedef std::true_type can_read;
@ -277,7 +281,7 @@ struct functor<T, Func, std::enable_if_t<std::is_member_object_pointer<Func>::va
template<typename T, typename Func>
struct functor<T, Func, std::enable_if_t<std::is_member_function_pointer<Func>::value>> {
typedef meta::bind_traits<Func> traits_type;
typedef typename traits_type::args_type args_type;
typedef typename traits_type::args_list args_list;
typedef typename traits_type::return_type return_type;
static const std::size_t arity = traits_type::arity;
static const bool is_free = false;

View File

@ -30,14 +30,14 @@ template<typename Func>
struct free_function : public base_function {
typedef meta::unwrapped_t<meta::unqualified_t<Func>> Function;
typedef meta::function_return_t<Function> return_type;
typedef meta::function_args_t<Function> args_types;
typedef meta::function_args_t<Function> args_lists;
Function fx;
template<typename... Args>
free_function(Args&&... args): fx(std::forward<Args>(args)...) {}
int call(lua_State* L) {
return stack::call_into_lua(meta::tuple_types<return_type>(), args_types(), L, 1, fx);
return stack::call_into_lua(meta::tuple_types<return_type>(), args_lists(), L, 1, fx);
}
virtual int operator()(lua_State* L) override {
@ -51,14 +51,14 @@ struct functor_function : public base_function {
typedef meta::unwrapped_t<meta::unqualified_t<Func>> Function;
typedef decltype(&Function::operator()) function_type;
typedef meta::function_return_t<function_type> return_type;
typedef meta::function_args_t<function_type> args_types;
typedef meta::function_args_t<function_type> args_lists;
Function fx;
template<typename... Args>
functor_function(Args&&... args): fx(std::forward<Args>(args)...) {}
int call(lua_State* L) {
return stack::call_into_lua(meta::tuple_types<return_type>(), args_types(), L, 1, fx);
return stack::call_into_lua(meta::tuple_types<return_type>(), args_lists(), L, 1, fx);
}
virtual int operator()(lua_State* L) override {
@ -71,7 +71,7 @@ template<typename T, typename Function>
struct member_function : public base_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef meta::function_return_t<function_type> return_type;
typedef meta::function_args_t<function_type> args_types;
typedef meta::function_args_t<function_type> args_lists;
struct functor {
function_type invocation;
T member;
@ -90,7 +90,7 @@ struct member_function : public base_function {
member_function(F&& f, Args&&... args) : fx(std::forward<F>(f), std::forward<Args>(args)...) {}
int call(lua_State* L) {
return stack::call_into_lua(meta::tuple_types<return_type>(), args_types(), L, 1, fx);
return stack::call_into_lua(meta::tuple_types<return_type>(), args_lists(), L, 1, fx);
}
virtual int operator()(lua_State* L) override {
@ -103,7 +103,7 @@ template<typename T, typename Function>
struct member_variable : public base_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef typename meta::bind_traits<function_type>::return_type return_type;
typedef typename meta::bind_traits<function_type>::args_type args_types;
typedef typename meta::bind_traits<function_type>::args_list args_lists;
function_type var;
T member;
typedef std::add_lvalue_reference_t<meta::unwrapped_t<std::remove_reference_t<decltype(detail::deref(member))>>> M;

View File

@ -36,7 +36,7 @@ struct overload_traits : lua_bind_traits<T> {
template <typename T, typename Func, typename X>
struct overload_traits<functor<T, Func, X>> {
typedef typename functor<T, Func, X>::args_type args_type;
typedef typename functor<T, Func, X>::args_list args_list;
typedef typename functor<T, Func, X>::return_type return_type;
static const std::size_t arity = functor<T, Func, X>::arity;
static const std::size_t boost = static_cast<std::size_t>(functor<T, Func, X>::is_free);
@ -51,8 +51,8 @@ template <typename Fx, typename... Fxs, std::size_t I, std::size_t... In, std::s
inline int overload_match_arity(types<Fx, Fxs...>, std::index_sequence<I, In...>, std::index_sequence<M...>, Match&& matchfx, lua_State* L, int nfxarity, int start, Args&&... args) {
typedef overload_traits<meta::unqualified_t<Fx>> traits;
typedef meta::tuple_types<typename traits::return_type> return_types;
typedef typename traits::args_type args_type;
typedef typename args_type::indices args_indices;
typedef typename traits::args_list args_list;
typedef typename args_list::indices args_indices;
int fxarity = traits::boost + nfxarity;
// compile-time eliminate any functions that we know ahead of time are of improper arity
if (meta::find_in_pack_v<index_value<traits::arity>, index_value<M>...>::value) {
@ -61,10 +61,10 @@ inline int overload_match_arity(types<Fx, Fxs...>, std::index_sequence<I, In...>
if (traits::arity != fxarity) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<traits::arity, M...>(), std::forward<Match>(matchfx), L, nfxarity, start, std::forward<Args>(args)...);
}
if (!stack::stack_detail::check_types<true>().check(args_type(), args_indices(), L, start - traits::boost, no_panic)) {
if (!stack::stack_detail::check_types<true>().check(args_list(), args_indices(), L, start - traits::boost, no_panic)) {
return overload_match_arity(types<Fxs...>(), std::index_sequence<In...>(), std::index_sequence<M...>(), std::forward<Match>(matchfx), L, nfxarity, start, std::forward<Args>(args)...);
}
return matchfx(types<Fx>(), index_value<I>(), return_types(), args_type(), L, fxarity, start, std::forward<Args>(args)...);
return matchfx(types<Fx>(), index_value<I>(), return_types(), args_list(), L, fxarity, start, std::forward<Args>(args)...);
}
} // internals

View File

@ -29,9 +29,9 @@ namespace function_detail {
template <typename F, F fx>
inline int call_wrapper_variable(std::false_type, lua_State* L) {
typedef meta::bind_traits<meta::unqualified_t<F>> traits_type;
typedef typename traits_type::args_type args_type;
typedef typename traits_type::args_list args_list;
typedef meta::tuple_types<typename traits_type::return_type> return_type;
return stack::call_into_lua(return_type(), args_type(), L, 1, fx);
return stack::call_into_lua(return_type(), args_list(), L, 1, fx);
}
template <typename R, typename V, V, typename T>
@ -86,14 +86,14 @@ namespace function_detail {
inline int call_wrapper_function(std::true_type, lua_State* L) {
typedef meta::bind_traits<meta::unqualified_t<F>> traits_type;
typedef typename traits_type::object_type T;
typedef typename traits_type::args_type args_type;
typedef typename traits_type::args_list args_list;
typedef typename traits_type::return_type return_type;
typedef meta::tuple_types<return_type> return_type_list;
auto mfx = [&](auto&&... args) -> typename traits_type::return_type {
auto& member = stack::get<T>(L, 1);
return (member.*fx)(std::forward<decltype(args)>(args)...);
};
int n = stack::call_into_lua<1>(return_type_list(), args_type(), L, 2, mfx);
int n = stack::call_into_lua<1>(return_type_list(), args_list(), L, 2, mfx);
return n;
}

View File

@ -34,7 +34,7 @@ struct usertype_function_core : public base_function {
typedef std::remove_pointer_t<std::decay_t<Function>> function_type;
typedef functor<T, function_type> fx_t;
typedef typename fx_t::traits_type traits_type;
typedef typename fx_t::args_type args_type;
typedef typename fx_t::args_list args_list;
typedef typename fx_t::return_type return_type;
fx_t fx;
@ -53,7 +53,7 @@ struct usertype_function : public usertype_function_core<Tp, Function> {
typedef usertype_function_core<Tp, Function> base_t;
typedef std::remove_pointer_t<Tp> T;
typedef typename base_t::traits_type traits_type;
typedef typename base_t::args_type args_type;
typedef typename base_t::args_list args_list;
typedef typename base_t::return_type return_type;
template<typename... Args>
@ -66,7 +66,7 @@ struct usertype_function : public usertype_function_core<Tp, Function> {
return luaL_error(L, "sol: received null for 'self' argument (use ':' for accessing member functions)");
}
#endif // Safety
return static_cast<base_t&>(*this)(meta::tuple_types<return_type>(), args_type(), index_value<2>(), L);
return static_cast<base_t&>(*this)(meta::tuple_types<return_type>(), args_list(), index_value<2>(), L);
}
virtual int operator()(lua_State* L) override {
@ -80,7 +80,7 @@ struct usertype_variable_function : public usertype_function_core<Tp, Function>
typedef std::remove_pointer_t<Tp> T;
typedef typename base_t::fx_t fx_t;
typedef typename base_t::traits_type traits_type;
typedef typename base_t::args_type args_type;
typedef typename base_t::args_list args_list;
typedef typename base_t::return_type return_type;
typedef typename fx_t::can_read can_read;
typedef typename fx_t::can_write can_write;
@ -103,7 +103,7 @@ struct usertype_variable_function : public usertype_function_core<Tp, Function>
}
int set_writable(std::true_type, lua_State* L) {
return static_cast<base_t&>(*this)(meta::tuple_types<void>(), args_type(), index_value<3>(), L);
return static_cast<base_t&>(*this)(meta::tuple_types<void>(), args_list(), index_value<3>(), L);
}
int set_variable(std::false_type, lua_State* L) {

View File

@ -111,7 +111,7 @@ struct inheritance {
return ti != typeid(Base) || type_check(types<Bases...>(), ti);
}
static bool check(const std::type_info& ti) {
static bool type_check(const std::type_info& ti) {
return ti != typeid(T) || type_check(types<Bases...>(), ti);
}
@ -125,14 +125,14 @@ struct inheritance {
return ti != typeid(Base) ? type_cast(types<Bases...>(), data, ti) : static_cast<void*>(dynamic_cast<Base*>(static_cast<T*>(data)));
}
static void* cast(void* voiddata, const std::type_info& ti) {
static void* type_cast(void* voiddata, const std::type_info& ti) {
T* data = static_cast<T*>(voiddata);
return static_cast<void*>(ti != typeid(T) ? type_cast(types<Bases...>(), data, ti) : data);
}
};
using inheritance_check_function = decltype(&inheritance<void>::check);
using inheritance_cast_function = decltype(&inheritance<void>::cast);
using inheritance_check_function = decltype(&inheritance<void>::type_check);
using inheritance_cast_function = decltype(&inheritance<void>::type_cast);
#else
template <typename T, typename... Bases>
struct inheritance {
@ -145,7 +145,7 @@ struct inheritance {
return ti != id_for<Base>::value || type_check(types<Bases...>(), ti);
}
static bool check(std::size_t ti) {
static bool type_check(std::size_t ti) {
return ti != id_for<T>::value || type_check(types<Bases...>(), ti);
}
@ -159,14 +159,14 @@ struct inheritance {
return ti != id_for<Base>::value ? type_cast(types<Bases...>(), data, ti) : static_cast<void*>(static_cast<Base*>(data));
}
static void* cast(void* voiddata, std::size_t ti) {
static void* type_cast(void* voiddata, std::size_t ti) {
T* data = static_cast<T*>(voiddata);
return static_cast<void*>(ti != id_for<T>::value ? type_cast(types<Bases...>(), data, ti) : data);
}
};
using inheritance_check_function = decltype(&inheritance<void>::check);
using inheritance_cast_function = decltype(&inheritance<void>::cast);
using inheritance_check_function = decltype(&inheritance<void>::type_check);
using inheritance_cast_function = decltype(&inheritance<void>::type_cast);
#endif // No Exceptions and/or No Runtime Type Information
} // detail

85
sol/property.hpp Normal file
View File

@ -0,0 +1,85 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_PROPERTY_HPP
#define SOL_PROPERTY_HPP
namespace sol {
struct no_prop { };
template <typename R, typename W>
struct property_wrapper {
typedef std::integral_constant<bool, !std::is_void<R>::value> can_read;
typedef std::integral_constant<bool, !std::is_void<W>::value> can_write;
typedef std::conditional_t<can_read::value, R, no_prop> Read;
typedef std::conditional_t<can_write::value, W, no_prop> Write;
Read read;
Write write;
template <typename Rx, typename Wx>
property_wrapper(Rx&& r, Wx&& w) : read(std::forward<Rx>(r)), write(std::forward<Wx>(w)) {}
};
namespace property_detail {
template <typename R, typename W>
inline decltype(auto) property(std::true_type, R&& read, W&& write) {
return property_wrapper<std::decay_t<R>, std::decay_t<W>>(std::forward<R>(read), std::forward<W>(write));
}
template <typename W, typename R>
inline decltype(auto) property(std::false_type, W&& write, R&& read) {
return property_wrapper<std::decay_t<R>, std::decay_t<W>>(std::forward<R>(read), std::forward<W>(write));
}
template <typename R>
inline decltype(auto) property(std::true_type, R&& read) {
return property_wrapper<std::decay_t<R>, void>(std::forward<R>(read), no_prop());
}
template <typename W>
inline decltype(auto) property(std::false_type, W&& write) {
return property_wrapper<void, std::decay_t<W>>(no_prop(), std::forward<W>(write));
}
} // property_detail
template <typename F, typename G>
inline decltype(auto) property(F&& f, G&& g) {
using namespace sol;
typedef lua_bind_traits<meta::unqualified_t<F>> left_traits;
typedef lua_bind_traits<meta::unqualified_t<G>> right_traits;
return property_detail::property(meta::boolean<(left_traits::arity < right_traits::arity)>(), std::forward<F>(f), std::forward<G>(g));
}
template <typename F>
inline decltype(auto) property(F&& f) {
using namespace sol;
typedef lua_bind_traits<meta::unqualified_t<F>> left_traits;
return property_detail::property(meta::boolean<(left_traits::arity == 0)>(), std::forward<F>(f));
}
// Allow someone to make a member variable readonly (const)
template <typename R, typename T>
auto readonly(R T::* v) {
typedef const R C;
return static_cast<C T::*>(v);
}
} // sol
#endif // SOL_PROPERTY_HPP

View File

@ -26,6 +26,7 @@
#include "stack.hpp"
#include "protected_function_result.hpp"
#include <cstdint>
#include <algorithm>
namespace sol {
template <typename base_t>
@ -86,7 +87,7 @@ private:
protected_function_result invoke(types<>, std::index_sequence<>, std::ptrdiff_t n, handler& h) const {
int stacksize = lua_gettop(base_t::lua_state());
int firstreturn = std::max(1, stacksize - static_cast<int>(n) - 1);
int firstreturn = (std::max)(1, stacksize - static_cast<int>(n) - 1);
int returncount = 0;
call_status code = call_status::ok;
#ifndef SOL_NO_EXCEPTIONS

View File

@ -55,20 +55,20 @@ private:
return stack::get<T>(L, index);
}
sol::optional<sol::error> tagged_get( types<sol::optional<sol::error>> ) const {
optional<error> tagged_get( types<optional<error>> ) const {
if (valid()) {
return nullopt;
}
return sol::error(detail::direct_error, stack::get<std::string>(L, index));
return error(detail::direct_error, stack::get<std::string>(L, index));
}
sol::error tagged_get( types<sol::error> ) const {
error tagged_get( types<error> ) const {
#ifdef SOL_CHECK_ARGUMENTS
if (valid()) {
type_panic(L, index, type_of(L, index), type::none);
}
#endif // Check Argument Safety
return sol::error(detail::direct_error, stack::get<std::string>(L, index));
return error(detail::direct_error, stack::get<std::string>(L, index));
}
public:

View File

@ -162,6 +162,14 @@ inline int call_into_lua(types<Ret0, Ret...>, types<Args...> ta, lua_State* L, i
return push_reference(L, std::forward<decltype(r)>(r));
}
template<int additionalpop = 0, bool check_args = stack_detail::default_check_arguments, typename Fx, typename... FxArgs>
inline int call_lua(lua_State* L, int start, Fx&& fx, FxArgs&&... fxargs) {
typedef lua_bind_traits<meta::unqualified_t<Fx>> traits_type;
typedef typename traits_type::args_list args_list;
typedef typename traits_type::returns_list returns_list;
return call_into_lua(returns_list(), args_list(), start, std::forward<Fx>(fx), std::forward<FxArgs>(fxargs)...)
}
inline call_syntax get_call_syntax(lua_State* L, const std::string& key, int index = -2) {
luaL_getmetatable(L, key.c_str());
if (lua_compare(L, -1, index, LUA_OPEQ) == 1) {

View File

@ -164,6 +164,23 @@ struct checker<T, type::lightuserdata, C> {
}
};
template <typename C>
struct checker<userdata_value, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler) {
type t = type_of(L, index);
bool success = t == type::userdata;
if (!success) {
// expected type, actual type
handler(L, index, type::userdata, t);
}
return success;
}
};
template <typename T, typename C>
struct checker<user<T>, type::userdata, C> : checker<user<T>, type::lightuserdata, C> {};
template <typename T, typename C>
struct checker<non_null<T>, type::userdata, C> : checker<T, lua_type_of<T>::value, C> {};
@ -235,77 +252,63 @@ struct checker<T*, type::userdata, C> {
}
};
template <typename C>
struct checker<userdata_value, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler) {
type t = type_of(L, index);
bool success = t == type::userdata || t == type::lightuserdata;
if (!success) {
// expected type, actual type
handler(L, index, type::lightuserdata, t);
}
return success;
}
};
template <typename T, typename C>
struct checker<T, type::userdata, C> {
template <typename U, typename Handler>
static bool check (types<U>, lua_State* L, type indextype, int index, Handler&& handler) {
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype);
return false;
}
if (meta::any<std::is_same<T, light_userdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value)
return true;
if (lua_getmetatable(L, index) == 0) {
return true;
}
if (stack_detail::check_metatable<U>(L))
return true;
if (stack_detail::check_metatable<U*>(L))
return true;
if (stack_detail::check_metatable<detail::unique_usertype<U>>(L))
return true;
template <typename U, typename Handler>
static bool check(types<U>, lua_State* L, type indextype, int index, Handler&& handler) {
if (indextype != type::userdata) {
handler(L, index, type::userdata, indextype);
return false;
}
if (meta::any<std::is_same<T, light_userdata_value>, std::is_same<T, userdata_value>, std::is_same<T, userdata>, std::is_same<T, lightuserdata>>::value)
return true;
if (lua_getmetatable(L, index) == 0) {
return true;
}
if (stack_detail::check_metatable<U>(L))
return true;
if (stack_detail::check_metatable<U*>(L))
return true;
if (stack_detail::check_metatable<detail::unique_usertype<U>>(L))
return true;
#ifndef SOL_NO_EXCEPTIONS
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
void* basecastdata = lua_touserdata(L, -1);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
bool success = detail::catch_check<T>(basecast);
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
void* basecastdata = lua_touserdata(L, -1);
detail::throw_cast basecast = (detail::throw_cast)basecastdata;
bool success = detail::catch_check<T>(basecast);
#elif !defined(SOL_NO_RTTI)
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 2);
return false;
}
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
bool success = ic(typeid(T));
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 2);
return false;
}
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
bool success = ic(typeid(T));
#else
// Topkek
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 2);
return false;
}
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
bool success = ic(detail::id_for<T>::value);
// Topkek
lua_getfield(L, -1, &detail::base_class_check_key()[0]);
if (stack::get<type>(L) == type::nil) {
lua_pop(L, 2);
return false;
}
void* basecastdata = lua_touserdata(L, -1);
detail::inheritance_check_function ic = (detail::inheritance_check_function)basecastdata;
bool success = ic(detail::id_for<T>::value);
#endif // No Runtime Type Information || Exceptions
lua_pop(L, 2);
if (!success) {
handler(L, index, type::userdata, indextype);
return false;
}
return true;
}
lua_pop(L, 2);
if (!success) {
handler(L, index, type::userdata, indextype);
return false;
}
return true;
}
template <typename Handler>
static bool check (lua_State* L, int index, Handler&& handler) {
const type indextype = type_of(L, index);
return check(types<T>(), L, indextype, index, std::forward<Handler>(handler));
}
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler) {
const type indextype = type_of(L, index);
return check(types<T>(), L, indextype, index, std::forward<Handler>(handler));
}
};
template<typename T>

View File

@ -52,30 +52,44 @@ struct check_getter<optional<T>> {
template <typename T>
struct check_getter<T, std::enable_if_t<std::is_integral<T>::value && lua_type_of<T>::value == type::number>> {
template <typename Handler>
static optional<T> get( lua_State* L, int index, Handler&& handler) {
int isnum = 0;
lua_Integer value = lua_tointegerx(L, index, &isnum);
if (isnum == 0) {
handler(L, index, type::number, type_of(L, index));
return nullopt;
}
return static_cast<T>(value);
}
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler) {
int isnum = 0;
lua_Integer value = lua_tointegerx(L, index, &isnum);
if (isnum == 0) {
handler(L, index, type::number, type_of(L, index));
return nullopt;
}
return static_cast<T>(value);
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<std::is_enum<T>::value>> {
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler) {
int isnum = 0;
lua_Integer value = lua_tointegerx(L, index, &isnum);
if (isnum == 0) {
handler(L, index, type::number, type_of(L, index));
return nullopt;
}
return static_cast<T>(value);
}
};
template <typename T>
struct check_getter<T, std::enable_if_t<std::is_floating_point<T>::value>> {
template <typename Handler>
static optional<T> get( lua_State* L, int index, Handler&& handler) {
int isnum = 0;
lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum == 0) {
handler(L, index, type::number, type_of(L, index));
return nullopt;
}
return static_cast<T>(value);
}
template <typename Handler>
static optional<T> get(lua_State* L, int index, Handler&& handler) {
int isnum = 0;
lua_Number value = lua_tonumberx(L, index, &isnum);
if (isnum == 0) {
handler(L, index, type::number, type_of(L, index));
return nullopt;
}
return static_cast<T>(value);
}
};
template <typename T>

View File

@ -202,6 +202,14 @@ inline decltype(auto) tagged_get(types<optional<T>>, lua_State* L, int index = -
return stack_detail::unchecked_get<optional<T>>(L, index);
}
template <typename T>
inline int alloc_destroy(lua_State* L) {
void* rawdata = lua_touserdata(L, up_value_index(1));
T* data = static_cast<T*>(rawdata);
std::allocator<T> alloc;
alloc.destroy(data);
}
} // stack_detail
template<typename T>

View File

@ -62,6 +62,13 @@ struct getter<T, std::enable_if_t<meta::all<std::is_integral<T>, std::is_unsigne
}
};
template<typename T>
struct getter<T, std::enable_if_t<std::is_enum<T>::value>> {
static T get(lua_State* L, int index = -1) {
return static_cast<T>(lua_tointegerx(L, index, nullptr));
}
};
template<typename T>
struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> {
static T get(lua_State* L, int index = -1) {
@ -83,6 +90,27 @@ struct getter<light_userdata_value> {
}
};
template<typename T>
struct getter<light<T>> {
static light<T> get(lua_State* L, int index = -1) {
return light<T>( static_cast<T*>(lua_touserdata(L, index)) );
}
};
template<typename T>
struct getter<user<T>> {
static T& get(lua_State* L, int index = -1) {
return *static_cast<T*>(lua_touserdata(L, index));
}
};
template<typename T>
struct getter<user<T*>> {
static T* get(lua_State* L, int index = -1) {
return static_cast<T*>(lua_touserdata(L, index));
}
};
template<>
struct getter<type> {
static type get(lua_State *L, int index){
@ -106,6 +134,15 @@ struct getter<std::string> {
}
};
template <>
struct getter<string_detail::string_shim> {
string_detail::string_shim get(lua_State* L, int index) {
size_t len;
const char* p = lua_tolstring(L, index, &len);
return string_detail::string_shim(p, len);
}
};
template<>
struct getter<const char*> {
static const char* get(lua_State* L, int index = -1) {
@ -113,6 +150,17 @@ struct getter<const char*> {
}
};
template<>
struct getter<meta_function> {
static meta_function get(lua_State *L, int index) {
const char* name = getter<const char*>{}.get(L, index);
for (std::size_t i = 0; i < meta_function_names.size(); ++i)
if (meta_function_names[i] == name)
return static_cast<meta_function>(i);
return meta_function::construct;
}
};
template<>
struct getter<char> {
static char get(lua_State* L, int index = -1) {
@ -208,9 +256,9 @@ struct getter<lua_CFunction> {
template<>
struct getter<c_closure> {
static c_closure get(lua_State* L, int index = -1) {
return c_closure(lua_tocfunction(L, index), -1);
}
static c_closure get(lua_State* L, int index = -1) {
return c_closure(lua_tocfunction(L, index), -1);
}
};
template<>

View File

@ -31,44 +31,54 @@ namespace sol {
namespace stack {
template<typename T, typename>
struct pusher {
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
// Basically, we store all user-data like this:
// If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new
// data in the first sizeof(T*) bytes, and then however many bytes it takes to
// do the actual object. Things that are std::ref or plain T* are stored as
// just the sizeof(T*), and nothing else.
T** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
T*& referencereference = *pointerpointer;
T* allocationtarget = reinterpret_cast<T*>(pointerpointer + 1);
referencereference = allocationtarget;
std::allocator<T> alloc{};
alloc.construct(allocationtarget, std::forward<Args>(args)...);
luaL_newmetatable(L, &usertype_traits<T>::metatable[0]);
lua_setmetatable(L, -2);
return 1;
}
};
template <typename K, typename... Args>
static int push_keyed(lua_State* L, metatable_registry_key<K> k, Args&&... args) {
// Basically, we store all user-data like this:
// If it's a movable/copyable value (no std::ref(x)), then we store the pointer to the new
// data in the first sizeof(T*) bytes, and then however many bytes it takes to
// do the actual object. Things that are std::ref or plain T* are stored as
// just the sizeof(T*), and nothing else.
T** pointerpointer = static_cast<T**>(lua_newuserdata(L, sizeof(T*) + sizeof(T)));
T*& referencereference = *pointerpointer;
T* allocationtarget = reinterpret_cast<T*>(pointerpointer + 1);
referencereference = allocationtarget;
std::allocator<T> alloc{};
alloc.construct(allocationtarget, std::forward<Args>(args)...);
luaL_newmetatable(L, &k.key[0]);
lua_setmetatable(L, -2);
return 1;
}
template <>
struct pusher<detail::as_reference_tag> {
template <typename T>
static int push(lua_State* L, T&& obj) {
return stack::push(L, detail::ptr(obj));
}
template <typename... Args>
static int push(lua_State* L, Args&&... args) {
return push_keyed(L, meta_registry_key(&usertype_traits<T*>::metatable[0]), std::forward<Args>(args)...);
}
};
template<typename T>
struct pusher<T*> {
static int push(lua_State* L, T* obj) {
if (obj == nullptr)
return stack::push(L, nil);
T** pref = static_cast<T**>(lua_newuserdata(L, sizeof(T*)));
*pref = obj;
luaL_getmetatable(L, &usertype_traits<T*>::metatable[0]);
lua_setmetatable(L, -2);
return 1;
}
template <typename K>
static int push_keyed(lua_State* L, metatable_registry_key<K> k, T* obj) {
if (obj == nullptr)
return stack::push(L, nil);
T** pref = static_cast<T**>(lua_newuserdata(L, sizeof(T*)));
*pref = obj;
luaL_getmetatable(L, &k.key[0]);
lua_setmetatable(L, -2);
return 1;
}
static int push(lua_State* L, T* obj) {
return push_keyed(L, meta_registry_key(&usertype_traits<T*>::metatable[0]), obj);
}
};
template <>
struct pusher<detail::as_reference_tag> {
template <typename T>
static int push(lua_State* L, T&& obj) {
return stack::push(L, detail::ptr(obj));
}
};
template<typename T>
@ -127,6 +137,16 @@ struct pusher<T, std::enable_if_t<meta::all<std::is_integral<T>, std::is_signed<
}
};
template<typename T>
struct pusher<T, std::enable_if_t<std::is_enum<T>::value>> {
static int push(lua_State* L, const T& value) {
if (std::is_same<char, T>::value) {
return stack::push(L, static_cast<int>(value));
}
return stack::push(L, static_cast<std::underlying_type_t<T>>(value));
}
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::all<std::is_integral<T>, std::is_unsigned<T>>::value>> {
static int push(lua_State* L, const T& value) {
@ -136,7 +156,7 @@ struct pusher<T, std::enable_if_t<meta::all<std::is_integral<T>, std::is_unsigne
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::all<meta::has_begin_end<T>, meta::neg<meta::has_key_value_pair<T>>, meta::neg<std::is_base_of<reference, T>>>::value>> {
struct pusher<T, std::enable_if_t<meta::all<meta::has_begin_end<T>, meta::neg<meta::has_key_value_pair<T>>, meta::neg<meta::any<std::is_base_of<reference, T>, std::is_base_of<stack_reference, T>>>>::value>> {
static int push(lua_State* L, const T& cont) {
lua_createtable(L, static_cast<int>(cont.size()), 0);
int tableindex = lua_gettop(L);
@ -149,7 +169,7 @@ struct pusher<T, std::enable_if_t<meta::all<meta::has_begin_end<T>, meta::neg<me
};
template<typename T>
struct pusher<T, std::enable_if_t<meta::all<meta::has_begin_end<T>, meta::has_key_value_pair<T>, meta::neg<std::is_base_of<reference, T>>>::value>> {
struct pusher<T, std::enable_if_t<meta::all<meta::has_begin_end<T>, meta::has_key_value_pair<T>, meta::neg<meta::any<std::is_base_of<reference, T>, std::is_base_of<stack_reference, T>>>>::value>> {
static int push(lua_State* L, const T& cont) {
lua_createtable(L, static_cast<int>(cont.size()), 0);
int tableindex = lua_gettop(L);
@ -213,12 +233,26 @@ struct pusher<lua_CFunction> {
template<>
struct pusher<c_closure> {
static int push(lua_State* L, c_closure closure) {
lua_pushcclosure(L, closure.c_function, closure.upvalues);
static int push(lua_State* L, c_closure cc) {
lua_pushcclosure(L, cc.c_function, cc.upvalues);
return 1;
}
};
template<typename Arg, typename... Args>
struct pusher<closure<Arg, Args...>> {
template <std::size_t... I, typename T>
static int push(std::index_sequence<I...>, lua_State* L, T&& c) {
int pushcount = multi_push(L, detail::forward_get<I>(c.upvalues)...);
return stack::push(L, c_closure(c.c_function, pushcount));
}
template <typename T>
static int push(lua_State* L, T&& c) {
return push(std::make_index_sequence<1 + sizeof...(Args)>(), L, std::forward<T>(c));
}
};
template<>
struct pusher<void*> {
static int push(lua_State* L, void* userdata) {
@ -235,6 +269,31 @@ struct pusher<light_userdata_value> {
}
};
template<typename T>
struct pusher<light<T>> {
static int push(lua_State* L, light<T> l) {
lua_pushlightuserdata(L, static_cast<void*>(l.value));
return 1;
}
};
template<typename T>
struct pusher<user<T>> {
template <typename... Args>
static int push(lua_State* L, Args&&... args ) {
// A dumb pusher
void* rawdata = lua_newuserdata(L, sizeof(T));
std::allocator<T> alloc;
alloc.construct(static_cast<T*>(rawdata), std::forward<Args>(args)...);
lua_CFunction cdel = stack_detail::alloc_destroy<T>;
// Make sure we have a plain GC set for this data
lua_pushlightuserdata(L, rawdata);
lua_pushcclosure(L, cdel, 1);
lua_setfield(L, -2, "__gc");
return 1;
}
};
template<>
struct pusher<userdata_value> {
static int push(lua_State* L, userdata_value data) {
@ -276,6 +335,15 @@ struct pusher<std::string> {
}
};
template<>
struct pusher<meta_function> {
static int push(lua_State* L, meta_function m) {
const std::string& str = name_of(m);
lua_pushlstring(L, str.c_str(), str.size());
return 1;
}
};
#if 0

48
sol/string_shim.hpp Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include <cstddef>
#include <string>
namespace sol {
namespace string_detail {
struct string_shim {
std::size_t s;
const char* p;
string_shim(std::string& r) : string_shim(r.data(), r.size()) {}
string_shim(const char* p) : string_shim(p, std::char_traits<char>::length(p)) {}
string_shim(const char* p, std::size_t s) : s(s), p(p) {}
static int compare(const char* lhs_p, std::size_t lhs_sz, const char* rhs_p, std::size_t rhs_sz) {
int result = std::char_traits<char>::compare(lhs_p, rhs_p, lhs_sz < rhs_sz ? lhs_sz : rhs_sz);
if (result != 0)
return result;
if (lhs_sz < rhs_sz)
return -1;
if (lhs_sz > rhs_sz)
return 1;
return 0;
}
const char* data() const {
return p;
}
std::size_t size() const {
return s;
}
bool operator==(const string_shim& r) const {
return compare(p, s, r.data(), r.size()) == 0;
}
bool operator==(const char* r) const {
return compare(r, std::char_traits<char>::length(r), p, s) == 0;
}
bool operator==(const std::string& r) const {
return compare(r.data(), r.size(), p, s) == 0;
}
};
}
}

View File

@ -23,6 +23,7 @@
#define SOL_TRAITS_HPP
#include "tuple.hpp"
#include "bind_traits.hpp"
#include <type_traits>
#include <memory>
#include <functional>
@ -54,6 +55,9 @@ struct unwrapped<std::reference_wrapper<T>> {
typedef T type;
};
template<typename T>
using unwrapped_t = typename unwrapped<T>::type;
template<typename T>
struct remove_member_pointer;
@ -117,21 +121,6 @@ using enable = std::enable_if_t<all<Args...>::value, enable_t>;
template<typename... Args>
using disable = std::enable_if_t<neg<all<Args...>>::value, enable_t>;
template<typename T>
using unqualified = std::remove_cv<std::remove_reference_t<T>>;
template<typename T>
using unqualified_t = typename unqualified<T>::type;
template<typename T>
using unwrapped_t = typename unwrapped<T>::type;
template <std::size_t N, typename Tuple>
using tuple_element = std::tuple_element<N, unqualified_t<Tuple>>;
template <std::size_t N, typename Tuple>
using tuple_element_t = std::tuple_element_t<N, unqualified_t<Tuple>>;
template<typename V, typename... Vs>
struct find_in_pack_v : boolean<false> { };
@ -252,151 +241,11 @@ struct is_callable<T, true> {
static const bool value = sizeof(test<Derived>(0)) == sizeof(yes);
};
template<class F>
struct check_deducible_signature {
struct nat {};
template<class G>
static auto test(int) -> decltype(&G::operator(), void());
template<class>
static auto test(...) -> nat;
using type = std::is_void<decltype(test<F>(0))>;
};
} // meta_detail
template<class F>
struct has_deducible_signature : meta_detail::check_deducible_signature<F>::type { };
template<typename T>
struct is_callable : boolean<meta_detail::is_callable<T>::value> {};
namespace meta_detail {
template <std::size_t I, typename T>
struct void_tuple_element : meta::tuple_element<I, T> {};
template <std::size_t I>
struct void_tuple_element<I, std::tuple<>> { typedef void type; };
template <std::size_t I, typename T>
using void_tuple_element_t = typename void_tuple_element<I, T>::type;
template<typename Signature, bool b = has_deducible_signature<Signature>::value>
struct fx_traits {
static const bool is_member_function = false;
static const std::size_t arity = 0;
typedef types<> args_type;
typedef std::tuple<> args_tuple_type;
typedef void object_type;
typedef void function_pointer_type;
typedef void function_type;
typedef void free_function_pointer_type;
typedef void signature_type;
typedef void return_type;
template<std::size_t i>
using arg_at = void_tuple_element_t<i, args_tuple_type>;
};
template<typename Signature>
struct fx_traits<Signature, true> : fx_traits<decltype(&Signature::operator()), false> {};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...), false> {
static const std::size_t arity = sizeof...(Args);
static const bool is_member_function = true;
typedef T object_type;
typedef std::tuple<Args...> args_tuple_type;
typedef types<Args...> args_type;
typedef R(T::* function_pointer_type)(Args...);
typedef std::remove_pointer_t<function_pointer_type> function_type;
typedef R(*free_function_pointer_type)(Args...);
typedef R return_type;
typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
template<std::size_t i>
using arg_at = void_tuple_element_t<i, args_tuple_type>;
};
template<typename T, typename R, typename... Args>
struct fx_traits<R(T::*)(Args...) const, false> {
static const std::size_t arity = sizeof...(Args);
static const bool is_member_function = true;
typedef T object_type;
typedef std::tuple<Args...> args_tuple_type;
typedef types<Args...> args_type;
typedef R(T::* function_pointer_type)(Args...);
typedef std::remove_pointer_t<function_pointer_type> function_type;
typedef R(*free_function_pointer_type)(Args...);
typedef R return_type;
typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
template<std::size_t i>
using arg_at = void_tuple_element_t<i, args_tuple_type>;
};
template<typename R, typename... Args>
struct fx_traits<R(Args...), false> {
static const std::size_t arity = sizeof...(Args);
static const bool is_member_function = false;
typedef std::tuple<Args...> args_tuple_type;
typedef types<Args...> args_type;
typedef R(function_type)(Args...);
typedef R(*function_pointer_type)(Args...);
typedef R(*free_function_pointer_type)(Args...);
typedef R return_type;
typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
template<std::size_t i>
using arg_at = void_tuple_element_t<i, args_tuple_type>;
};
template<typename R, typename... Args>
struct fx_traits<R(*)(Args...), false> {
static const std::size_t arity = sizeof...(Args);
static const bool is_member_function = false;
typedef std::tuple<Args...> args_tuple_type;
typedef types<Args...> args_type;
typedef R(function_type)(Args...);
typedef R(*function_pointer_type)(Args...);
typedef R(*free_function_pointer_type)(Args...);
typedef R return_type;
typedef std::remove_pointer_t<free_function_pointer_type> signature_type;
template<std::size_t i>
using arg_at = void_tuple_element_t<i, args_tuple_type>;
};
template<typename Signature, bool b = std::is_member_object_pointer<Signature>::value>
struct callable_traits : fx_traits<std::decay_t<Signature>> {
};
template<typename R, typename T>
struct callable_traits<R(T::*), true> {
typedef R Arg;
typedef T object_type;
using signature_type = R(T::*);
static const bool is_member_function = false;
static const std::size_t arity = 1;
typedef std::tuple<Arg> args_tuple_type;
typedef types<Arg> args_type;
typedef R return_type;
typedef R(function_type)(Arg);
typedef R(*function_pointer_type)(Arg);
typedef R(*free_function_pointer_type)(Arg);
template<std::size_t i>
using arg_at = void_tuple_element_t<i, args_tuple_type>;
};
} // meta_detail
template<typename Signature>
struct bind_traits : meta_detail::callable_traits<std::remove_volatile_t<Signature>> {};
template<typename Signature>
using function_args_t = typename bind_traits<Signature>::args_type;
template<typename Signature>
using function_signature_t = typename bind_traits<Signature>::signature_type;
template<typename Signature>
using function_return_t = typename bind_traits<Signature>::return_type;
struct has_begin_end_impl {
template<typename T, typename U = unqualified_t<T>,
typename B = decltype(std::declval<U&>().begin()),

View File

@ -41,6 +41,12 @@ template<typename... Args>
struct tuple_types_<std::tuple<Args...>> { typedef types<Args...> type; };
} // detail
template<typename T>
using unqualified = std::remove_cv<std::remove_reference_t<T>>;
template<typename T>
using unqualified_t = typename unqualified<T>::type;
template<typename... Args>
using tuple_types = typename detail::tuple_types_<Args...>::type;
@ -50,8 +56,18 @@ struct pop_front_type;
template<typename Arg>
using pop_front_type_t = typename pop_front_type<Arg>::type;
template<typename... Args>
struct pop_front_type<types<Args...>> { typedef void front_type; typedef types<Args...> type; };
template<typename Arg, typename... Args>
struct pop_front_type<types<Arg, Args...>> { typedef types<Args...> type; };
struct pop_front_type<types<Arg, Args...>> { typedef Arg front_type; typedef types<Args...> type; };
template <std::size_t N, typename Tuple>
using tuple_element = std::tuple_element<N, unqualified_t<Tuple>>;
template <std::size_t N, typename Tuple>
using tuple_element_t = std::tuple_element_t<N, unqualified_t<Tuple>>;
} // meta
} // sol

View File

@ -22,9 +22,10 @@
#ifndef SOL_TYPES_HPP
#define SOL_TYPES_HPP
#include "optional.hpp"
#include "compatibility.hpp"
#include "traits.hpp"
#include "optional.hpp"
#include "string_shim.hpp"
#include <array>
#include <string>
@ -83,8 +84,6 @@ inline int c_trampoline(lua_State* L, lua_CFunction f) {
return trampoline(L, f);
}
#endif // Exceptions vs. No Exceptions
struct empty { void operator()() {} };
template <typename T>
struct unique_usertype {};
} // detail
@ -174,12 +173,72 @@ struct userdata_value {
operator void*() const { return value; }
};
struct c_closure {
lua_CFunction c_function;
int upvalues;
c_closure(lua_CFunction f, int upvalues = 0) : c_function(f), upvalues(upvalues) {}
template <typename L>
struct light {
L* value;
light(L& x) : value(std::addressof(x)) {}
light(L* x) : value(x) {}
light(void* x) : value(static_cast<L*>(x)) {}
operator L* () const { return value; }
operator L& () const { return *value; }
};
template <typename T>
auto make_light(T& l) {
typedef meta::unwrapped_t<std::remove_pointer_t<std::remove_pointer_t<T>>> L;
return light<L>(l);
}
template <typename U>
struct user {
U value;
user(U x) : value(std::forward<U>(x)) {}
operator U* () const { return std::addressof(value); }
operator U& () const { return value; }
};
template <typename T>
auto make_user(T&& u) {
typedef meta::unwrapped_t<meta::unqualified_t<T>> U;
return user<U>(std::forward<T>(u));
}
template <typename T>
struct metatable_registry_key {
T key;
metatable_registry_key(T key) : key(std::forward<T>(key)) {}
};
template <typename T>
auto meta_registry_key(T&& key) {
typedef meta::unqualified_t<T> K;
return metatable_registry_key<K>(std::forward<T>(key));
}
template <typename... Upvalues>
struct closure {
lua_CFunction c_function;
std::tuple<Upvalues...> upvalues;
closure(lua_CFunction f, Upvalues... upvalues) : c_function(f), upvalues(std::forward<Upvalues>(upvalues)...) {}
};
template <>
struct closure<> {
lua_CFunction c_function;
int upvalues;
closure(lua_CFunction f, int upvalues = 0) : c_function(f), upvalues(upvalues) {}
};
typedef closure<> c_closure;
template <typename... Args>
closure<Args...> make_closure(lua_CFunction f, Args&&... args) {
return closure<Args...>(f, std::forward<Args>(args)...);
}
struct this_state {
lua_State* L;
operator lua_State* () const {
@ -262,6 +321,8 @@ enum class meta_function {
call_function = call,
};
typedef meta_function meta_method;
const std::array<std::string, 2> meta_variable_names = { {
"__index",
"__newindex",
@ -320,7 +381,7 @@ inline void type_error(lua_State* L, type expected, type actual) {
inline void type_assert(lua_State* L, int index, type expected, type actual) {
if (expected != type::poly && expected != actual) {
type_panic(L, index, expected, actual);
type_panic(L, index, expected, actual);
}
}
@ -373,6 +434,7 @@ class thread;
struct variadic_args;
struct this_state;
namespace detail {
template <typename T, typename = void>
struct lua_type_of : std::integral_constant<type, type::userdata> {};
@ -421,6 +483,9 @@ struct lua_type_of<const char16_t*> : std::integral_constant<type, type::string>
template <>
struct lua_type_of<const char32_t*> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<string_detail::string_shim> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<bool> : std::integral_constant<type, type::boolean> {};
@ -457,6 +522,12 @@ struct lua_type_of<light_userdata_value> : std::integral_constant<type, type::li
template <>
struct lua_type_of<userdata_value> : std::integral_constant<type, type::userdata> {};
template <typename T>
struct lua_type_of<light<T>> : std::integral_constant<type, type::lightuserdata> {};
template <typename T>
struct lua_type_of<user<T>> : std::integral_constant<type, type::userdata> {};
template <typename Base>
struct lua_type_of<basic_lightuserdata<Base>> : std::integral_constant<type, type::lightuserdata> {};
@ -499,8 +570,15 @@ struct lua_type_of<T, std::enable_if_t<std::is_arithmetic<T>::value>> : std::int
template <typename T>
struct lua_type_of<T, std::enable_if_t<std::is_enum<T>::value>> : std::integral_constant<type, type::number> {};
template <>
struct lua_type_of<sol::meta_function> : std::integral_constant<type, type::string> {};
template <>
struct lua_type_of<this_state> : std::integral_constant<type, type::none> {};
} // detail
template <typename T>
struct lua_type_of : detail::lua_type_of<T> {};
template <typename T>
struct is_lua_primitive : std::integral_constant<bool,
@ -544,7 +622,10 @@ struct lua_bind_traits : meta::bind_traits<Signature> {
private:
typedef meta::bind_traits<Signature> base_t;
public:
static const std::size_t arity = base_t::arity - meta::count_for<is_transparent_argument, typename base_t::args_type>::value;
static const std::size_t true_arity = base_t::arity;
static const std::size_t arity = base_t::arity - meta::count_for<is_transparent_argument, typename base_t::args_list>::value;
static const std::size_t true_free_arity = base_t::free_arity;
static const std::size_t free_arity = base_t::free_arity - meta::count_for<is_transparent_argument, typename base_t::args_list>::value;
};
template <typename T>
@ -555,7 +636,7 @@ struct is_table<basic_table_core<x, T>> : std::true_type {};
template<typename T>
inline type type_of() {
return lua_type_of<meta::unqualified_t<T>>::value;
return lua_type_of<meta::unqualified_t<T>>::value;
}
} // sol

View File

@ -28,6 +28,8 @@
#include "inheritance.hpp"
#include "raii.hpp"
#include "deprecate.hpp"
#include "usertype_metatable.hpp"
#include "stack.hpp"
#include <vector>
#include <array>
#include <algorithm>
@ -422,13 +424,13 @@ private:
#elif !defined(SOL_NO_RTTI)
static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
baseclasscheck = (void*)&detail::inheritance<T, Bases...>::check;
baseclasscast = (void*)&detail::inheritance<T, Bases...>::cast;
baseclasscheck = (void*)&detail::inheritance<T, Bases...>::type_check;
baseclasscast = (void*)&detail::inheritance<T, Bases...>::type_cast;
#else
static_assert(sizeof(void*) <= sizeof(detail::inheritance_check_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
static_assert(sizeof(void*) <= sizeof(detail::inheritance_cast_function), "The size of this data pointer is too small to fit the inheritance checking function: file a bug report.");
baseclasscheck = (void*)&detail::inheritance<T, Bases...>::check;
baseclasscast = (void*)&detail::inheritance<T, Bases...>::cast;
baseclasscheck = (void*)&detail::inheritance<T, Bases...>::type_check;
baseclasscast = (void*)&detail::inheritance<T, Bases...>::type_cast;
#endif // No Runtime Type Information vs. Throw-Style Inheritance
}

187
sol/usertype_metatable.hpp Normal file
View File

@ -0,0 +1,187 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_USERTYPE_METATABLE_HPP
#define SOL_USERTYPE_METATABLE_HPP
#include "wrapper.hpp"
#include "call.hpp"
#include "stack.hpp"
#include "types.hpp"
namespace sol {
namespace usertype_detail {
inline bool is_index(string_detail::string_shim s) {
return s == name_of(meta_function::index) || s == name_of(meta_function::new_index);
}
inline bool is_index(meta_function mf) {
return mf == meta_function::index || mf == meta_function::new_index;
}
}
template <typename T, typename Tuple>
struct usertype_metatable {
typedef std::make_index_sequence<std::tuple_size<Tuple>::value> indices;
typedef std::make_index_sequence<std::tuple_size<Tuple>::value / 2> half_indices;
template <std::size_t I>
struct check_binding : is_variable_binding<std::tuple_element_t<I, Tuple>> {};
Tuple functions;
bool must_index;
template <std::size_t... I>
static bool contains_variable(std::index_sequence<I...>) {
typedef meta::any<check_binding<(I * 2 + 1)>...> has_variables;
return has_variables::value;
}
template <std::size_t... I>
bool contains_index(std::index_sequence<I...>) const {
bool idx = false;
detail::swallow{ 0, ((idx &= usertype_detail::is_index(std::get<I * 2>(functions))), 0) ... };
return idx;
}
usertype_metatable(Tuple t) : functions(std::move(t)), must_index(contains_variable(half_indices()) || contains_index(half_indices())) {}
template <bool is_index>
int find_call(std::integral_constant<bool, is_index>, std::index_sequence<>, lua_State* L, const sol::string_detail::string_shim& accessor) {
return luaL_error(L, "sol: attempt to index nil value \"%s\" on userdata (bad (misspelled?) key name or does not exist)", accessor.data());
}
template <bool is_index, std::size_t I0, std::size_t I1, std::size_t... In>
int find_call(std::integral_constant<bool, is_index> idx, std::index_sequence<I0, I1, In...>, lua_State* L, const sol::string_detail::string_shim& accessor) {
string_detail::string_shim name(std::get<I0>(functions));
if (accessor == name) {
if (is_variable_binding<decltype(std::get<I1>(functions))>::value) {
return call_with<I1, is_index, true>(L, *this);
}
return stack::push(L, c_closure(call<I1, is_index>, stack::push(L, light<usertype_metatable>(*this))));
}
return find_call(idx, std::index_sequence<In...>(), L, accessor);
}
template <std::size_t I, bool is_index = true, bool is_variable = false>
static int call(lua_State* L) {
usertype_metatable& f = stack::get<light<usertype_metatable>>(L, up_value_index(1));
return call_with<I, is_index, is_variable>(L, f);
}
template <std::size_t I, bool is_index = true, bool is_variable = false>
static int call_with(lua_State* L, usertype_metatable& um) {
auto& f = call_detail::pick(std::integral_constant<bool, is_index>(), std::get<I>(um.functions));
return call_detail::call_wrapped<T, is_index, is_variable>(L, f);
}
static int index_call(lua_State* L) {
usertype_metatable& f = stack::get<light<usertype_metatable>>(L, up_value_index(1));
string_detail::string_shim accessor = stack::get<string_detail::string_shim>(L, -1);
return f.find_call(std::true_type(), std::make_index_sequence<std::tuple_size<Tuple>::value>(), L, accessor);
}
static int new_index_call(lua_State* L) {
usertype_metatable& f = stack::get<light<usertype_metatable>>(L, up_value_index(1));
string_detail::string_shim accessor = stack::get<string_detail::string_shim>(L, -2);
return f.find_call(std::false_type(), std::make_index_sequence<std::tuple_size<Tuple>::value>(), L, accessor);
}
static int gc_call(lua_State* L) {
stack_object o(L, 1);
type x = o.get_type();
usertype_metatable& f = stack::get<light<usertype_metatable>>(L, up_value_index(1));
f.~usertype_metatable();
return 0;
}
};
namespace stack {
template <typename T, typename Tuple>
struct pusher<usertype_metatable<T, Tuple>> {
typedef usertype_metatable<T, Tuple> umt_t;
static void cleanup(lua_State* L, int metaidx, usertype_metatable<T, Tuple>&& um) {
const char* metakey = &usertype_traits<T>::gc_table[0];
lua_createtable(L, 1, 0);
stack_table t(L, -1);
t[meta_function::garbage_collect] = umt_t::gc_call;
stack::set_field(L, metakey, t, metaidx);
}
template <std::size_t... I>
static int push(std::index_sequence<I...>, lua_State* L, usertype_metatable<T, Tuple>&& um) {
// Basic index pushing: specialize
// index and newindex to give variables and stuff
// make sure to return final T metatable table
const bool mustindex = um.must_index;
for (std::size_t i = 0; i < 3; ++i) {
// Pointer types, AKA "references" from C++
const char* metakey = nullptr;
switch (i) {
case 0:
metakey = &usertype_traits<T*>::metatable[0];
break;
case 1:
metakey = &usertype_traits<detail::unique_usertype<T>>::metatable[0];
break;
case 2:
default:
metakey = &usertype_traits<T>::metatable[0];
break;
}
luaL_newmetatable(L, metakey);
stack_table t(L, -1);
stack::push(L, make_light(um));
luaL_Reg l[] = {
{ &std::get<I * 2>(um.functions)[0], umt_t::call<(I * 2) + 1> }...,
{ nullptr, nullptr }
};
luaL_setfuncs(L, l, 1);
if (mustindex) {
t[meta_function::index] = make_closure(umt_t::index_call, make_light(um));
t[meta_function::new_index] = make_closure(umt_t::new_index_call, make_light(um));
}
else {
t[meta_function::index] = t;
}
if (i < 2) {
// We want to just leave the table
// in the registry only, otherwise we return it
t.pop();
}
}
int metaidx = lua_gettop(L);
cleanup(L, metaidx, std::move(um));
return 1;
}
static int push(lua_State* L, usertype_metatable<T, Tuple>&& um) {
return push(std::make_index_sequence<std::tuple_size<Tuple>::value / 2>(), L, std::move(um));
}
};
} // stack
} // sol
#endif // SOL_USERTYPE_METATABLE_HPP

View File

@ -41,7 +41,7 @@ namespace sol {
int stacktop;
stack_proxy sp;
va_iterator() : L(nullptr), index(std::numeric_limits<int>::max()), stacktop(std::numeric_limits<int>::max()) {}
va_iterator() : L(nullptr), index((std::numeric_limits<int>::max)()), stacktop((std::numeric_limits<int>::max)()) {}
va_iterator(lua_State* L, int index, int stacktop) : L(L), index(index), stacktop(stacktop), sp(L, index) {}
reference operator*() {
@ -100,10 +100,10 @@ namespace sol {
}
bool operator==(const va_iterator& r) const {
if (stacktop == std::numeric_limits<int>::max()) {
if (stacktop == (std::numeric_limits<int>::max)()) {
return r.index == r.stacktop;
}
else if (r.stacktop == std::numeric_limits<int>::max()) {
else if (r.stacktop == (std::numeric_limits<int>::max)()) {
return index == stacktop;
}
return index == r.index;

209
sol/wrapper.hpp Normal file
View File

@ -0,0 +1,209 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_WRAPPER_HPP
#define SOL_WRAPPER_HPP
#include "types.hpp"
namespace sol {
template <typename F, typename = void>
struct wrapper {
typedef lua_bind_traits<F> traits_type;
typedef typename traits_type::args_list args_list;
typedef typename traits_type::args_list free_args_list;
typedef typename traits_type::returns_list returns_list;
template <typename Fx, typename... Args>
static decltype(auto) call(Fx&& fx, Args&&... args) {
return fx(std::forward<Args>(args)...);
}
struct caller {
template <typename Fx, typename... Args>
decltype(auto) operator()(Fx&& fx, Args&&... args) const {
return call(std::forward<Fx>(fx), std::forward<Args>(args)...);
}
};
};
template <typename F>
struct wrapper<F, std::enable_if_t<std::is_function<meta::unqualified_t<std::remove_pointer_t<F>>>::value>> {
typedef lua_bind_traits<F> traits_type;
typedef typename traits_type::args_list args_list;
typedef typename traits_type::args_list free_args_list;
typedef typename traits_type::returns_list returns_list;
template <F fx, typename... Args>
static decltype(auto) invoke(Args&&... args) {
return fx(std::forward<Args>(args)...);
}
template <typename Fx, typename... Args>
static decltype(auto) call(Fx&& fx, Args&&... args) {
return fx(std::forward<Args>(args)...);
}
struct caller {
template <typename Fx, typename... Args>
decltype(auto) operator()(Fx&& fx, Args&&... args) const {
return call(std::forward<Fx>(fx), std::forward<Args>(args)...);
}
};
};
template <typename F>
struct wrapper<F, std::enable_if_t<std::is_member_object_pointer<meta::unqualified_t<F>>::value>> {
typedef lua_bind_traits<F> traits_type;
typedef typename traits_type::object_type object_type;
typedef typename traits_type::return_type return_type;
typedef typename traits_type::args_list args_list;
typedef types<object_type&, return_type> free_args_list;
typedef typename traits_type::returns_list returns_list;
template <F fx, typename... Args>
static decltype(auto) invoke(object_type& mem, Args&&... args) {
return (mem.*fx)(std::forward<Args>(args)...);
}
template <typename Fx>
static decltype(auto) call(Fx&& fx, object_type& mem) {
return (mem.*fx);
}
template <typename Fx, typename Arg, typename... Args>
static void call(Fx&& fx, object_type& mem, Arg&& arg, Args&&... args) {
(mem.*fx) = std::forward<Arg>(arg);
}
struct caller {
template <typename Fx, typename... Args>
decltype(auto) operator()(Fx&& fx, object_type& mem, Args&&... args) const {
return call(std::forward<Fx>(fx), mem, std::forward<Args>(args)...);
}
};
};
template <typename F, typename R, typename O, typename... FArgs>
struct member_function_wrapper {
typedef O object_type;
typedef lua_bind_traits<F> traits_type;
typedef typename traits_type::args_list args_list;
typedef types<object_type&, FArgs...> free_args_list;
typedef meta::tuple_types<R> returns_list;
template <F fx, typename... Args>
static R invoke(O& mem, Args... args) {
return (mem.*fx)(std::forward<Args>(args)...);
}
template <typename Fx, typename... Args>
static R call(Fx&& fx, O& mem, Args... args) {
return (mem.*fx)(std::forward<Args>(args)...);
}
struct caller {
template <typename Fx, typename... Args>
decltype(auto) operator()(Fx&& fx, O& mem, Args&&... args) const {
return call(std::forward<Fx>(fx), mem, std::forward<Args>(args)...);
}
};
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args...)> : public member_function_wrapper<R(O:: *)(Args...), R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args...) const> : public member_function_wrapper<R(O:: *)(Args...) const, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args...) const volatile> : public member_function_wrapper<R(O:: *)(Args...) const volatile, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args...) &> : public member_function_wrapper<R(O:: *)(Args...) &, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args...) const &> : public member_function_wrapper<R(O:: *)(Args...) const &, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args...) const volatile &> : public member_function_wrapper<R(O:: *)(Args...) const volatile &, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args..., ...) &> : public member_function_wrapper<R(O:: *)(Args..., ...) &, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args..., ...) const &> : public member_function_wrapper<R(O:: *)(Args..., ...) const &, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args..., ...) const volatile &> : public member_function_wrapper<R(O:: *)(Args..., ...) const volatile &, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args...) && > : public member_function_wrapper<R(O:: *)(Args...) &, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args...) const &&> : public member_function_wrapper<R(O:: *)(Args...) const &, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args...) const volatile &&> : public member_function_wrapper<R(O:: *)(Args...) const volatile &, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args..., ...) && > : public member_function_wrapper<R(O:: *)(Args..., ...) &, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args..., ...) const &&> : public member_function_wrapper<R(O:: *)(Args..., ...) const &, R, O, Args...> {
};
template <typename R, typename O, typename... Args>
struct wrapper<R(O:: *)(Args..., ...) const volatile &&> : public member_function_wrapper<R(O:: *)(Args..., ...) const volatile &, R, O, Args...> {
};
} // sol
#endif // SOL_WRAPPER_HPP

View File

@ -4,7 +4,6 @@
#include <sol.hpp>
// There isn't a single library roundtripping with codecvt works on. We'll do the nitty-gritty of it later...
#if 0
TEST_CASE("stack/strings", "test that strings can be roundtripped") {
sol::state lua;
@ -12,7 +11,9 @@ TEST_CASE("stack/strings", "test that strings can be roundtripped") {
static const char16_t utf16str[] = { 0xD83C, 0xDF4C, 0x20, 0x6665, 0x20, 0x46, 0x6F, 0x6F, 0x20, 0xA9, 0x20, 0x62, 0x61, 0x72, 0x20, 0xD834, 0xDF06, 0x20, 0x62, 0x61, 0x7A, 0x20, 0x2603, 0x20, 0x71, 0x75, 0x78, 0x00 };
static const char32_t utf32str[] = { 0x1F34C, 0x0020, 0x6665, 0x0020, 0x0046, 0x006F, 0x006F, 0x0020, 0x00A9, 0x0020, 0x0062, 0x0061, 0x0072, 0x0020, 0x1D306, 0x0020, 0x0062, 0x0061, 0x007A, 0x0020, 0x2603, 0x0020, 0x0071, 0x0075, 0x0078, 0x00 };
static const wchar_t widestr[] = L"Fuck these shitty compilers";
static const char32_t utf32str2[] = U"🕴";
#if 0
lua["utf8"] = utf8str;
lua["utf16"] = utf16str;
lua["utf32"] = utf32str;
@ -67,5 +68,5 @@ TEST_CASE("stack/strings", "test that strings can be roundtripped") {
REQUIRE(utf16_to_char32 == utf32str[0]);
REQUIRE(utf32_to_char32 == utf32str[0]);
REQUIRE(wide_to_char32 == utf32str[0]);
}
#endif // Shit C++
}

View File

@ -359,7 +359,7 @@ TEST_CASE("state/multi-require", "make sure that requires transfers across hand-
int val1 = thingy1["modfunc"]();
int val2 = thingy2["modfunc"]();
int val3 = thingy2["modfunc"]();
int val3 = thingy3["modfunc"]();
REQUIRE(val1 == 221);
REQUIRE(val2 == 221);
REQUIRE(val3 == 221);