mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
We now have the ability to get a userdata that has been created C++ style out of lua
Using `auto` and `decltype` in more places that MSVC can handle it -- using type traits in other places to avoid VC++'s chokes More flexibility, woo!
This commit is contained in:
parent
d7ea4718c8
commit
ff7326ed96
149
sol/stack.hpp
149
sol/stack.hpp
|
@ -33,110 +33,112 @@
|
||||||
namespace sol {
|
namespace sol {
|
||||||
namespace stack {
|
namespace stack {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
inline nil_t get(types<nil_t>, lua_State* L, int index = -1) {
|
||||||
|
if (lua_isnil(L, index) == 0)
|
||||||
|
throw sol::sol_error("not nil");
|
||||||
|
return nil_t{ };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline lightuserdata_t get(types<lightuserdata_t>, lua_State* L, int index = -1) {
|
||||||
|
return{ lua_touserdata(L, lua_upvalueindex(index)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline userdata_t get(types<userdata_t>, lua_State* L, int index = -1) {
|
||||||
|
return{ lua_touserdata(L, index) };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string get(types<std::string>, lua_State* L, int index = -1) {
|
||||||
|
std::string::size_type len;
|
||||||
|
auto str = lua_tolstring(L, index, &len);
|
||||||
|
return{ str, len };
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* get(types<const char*>, lua_State* L, int index = -1) {
|
||||||
|
return lua_tostring(L, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline type get(types<type>, lua_State* L, int index = -1) {
|
||||||
|
return static_cast<type>(lua_type(L, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T& get(types<userdata<T>>, lua_State* L, int index = -1) {
|
||||||
|
userdata_t udata = get(types<userdata_t>{}, L, index);
|
||||||
|
T* obj = static_cast<T*>(udata.value);
|
||||||
|
return *obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T get(types<T>, lua_State* L, int index = -1) {
|
||||||
|
return T(L, index);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T get_unsigned(lua_State* L, std::true_type, int index = -1) {
|
inline T get_unsigned(std::true_type, lua_State* L, int index = -1) {
|
||||||
return lua_tounsigned(L, index);
|
return lua_tounsigned(L, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T get_unsigned(lua_State* L, std::false_type, int index = -1) {
|
inline T get_unsigned(std::false_type, lua_State* L, int index = -1) {
|
||||||
return static_cast<T>(lua_tointeger(L, index));
|
return static_cast<T>(lua_tointeger(L, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T get_arithmetic(lua_State* L, std::false_type, int index = -1) {
|
inline T get_arithmetic(std::false_type, lua_State* L, int index = -1) {
|
||||||
// T is a floating point
|
// T is a floating point
|
||||||
return static_cast<T>(lua_tonumber(L, index));
|
return static_cast<T>(lua_tonumber(L, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T get_arithmetic(lua_State* L, std::true_type, int index = -1) {
|
inline T get_arithmetic(std::true_type, lua_State* L, int index = -1) {
|
||||||
// T is an integral
|
// T is an integral
|
||||||
return get_unsigned<T>(L, std::is_unsigned<T>{}, index);
|
return get_unsigned<T>(std::is_unsigned<T>{}, L, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T get_nil(lua_State* L, std::true_type, int index = -1) {
|
inline T get_helper(std::true_type, lua_State* L, int index = -1) {
|
||||||
if (lua_isnil(L, index) == 0)
|
|
||||||
throw sol::sol_error("not nil");
|
|
||||||
return nil_t{};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline T get_nil(lua_State* L, std::false_type, int index = -1) {
|
|
||||||
// T is a class type
|
|
||||||
return T(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline T get_helper(lua_State* L, std::true_type, int index = -1) {
|
|
||||||
return get_nil<T>(L, std::is_same<nil_t, T>(), index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline T get_helper(lua_State* L, std::false_type, int index = -1) {
|
|
||||||
// T is a fundamental type
|
// T is a fundamental type
|
||||||
return get_arithmetic<T>(L, std::is_integral<T>{}, index);
|
return get_arithmetic<T>(std::is_integral<T>{}, L, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool get_helper<bool>(std::true_type, lua_State* L, int index) {
|
||||||
|
return lua_toboolean(L, index) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void push_unsigned(lua_State* L, T x, std::true_type) {
|
inline auto get_helper(std::false_type, lua_State* L, int index = -1) {
|
||||||
|
// T is a class
|
||||||
|
return get(types<T>(), L, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void push_unsigned(std::true_type, lua_State* L, T x) {
|
||||||
lua_pushunsigned(L, x);
|
lua_pushunsigned(L, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void push_unsigned(lua_State* L, T x, std::false_type) {
|
inline void push_unsigned(std::false_type, lua_State* L, T x) {
|
||||||
lua_pushinteger(L, x);
|
lua_pushinteger(L, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void push_arithmetic(lua_State* L, T x, std::true_type) {
|
inline void push_arithmetic(std::true_type, lua_State* L, T x) {
|
||||||
// T is an integral type
|
// T is an integral type
|
||||||
push_unsigned(L, x, std::is_unsigned<T>{});
|
push_unsigned(std::is_unsigned<T>{}, L, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline void push_arithmetic(lua_State* L, T x, std::false_type) {
|
inline void push_arithmetic(std::false_type, lua_State* L, T x) {
|
||||||
// T is an floating point type
|
// T is an floating point type
|
||||||
lua_pushnumber(L, x);
|
lua_pushnumber(L, x);
|
||||||
}
|
}
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T get(lua_State* L, int index = -1) {
|
inline auto get(lua_State* L, int index = -1)
|
||||||
return detail::get_helper<T>(L, std::is_class<T>{}, index);
|
-> decltype(detail::get_helper<T>(std::is_arithmetic<T>{}, L, index)) {
|
||||||
}
|
return detail::get_helper<T>(std::is_arithmetic<T>{}, L, index);
|
||||||
|
|
||||||
template<>
|
|
||||||
inline bool get<bool>(lua_State* L, int index) {
|
|
||||||
return lua_toboolean(L, index) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline lightuserdata_t get<lightuserdata_t>(lua_State* L, int index) {
|
|
||||||
return {lua_touserdata(L, lua_upvalueindex(index))};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline userdata_t get<userdata_t>(lua_State* L, int index) {
|
|
||||||
return {lua_touserdata(L, index)};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline std::string get<std::string>(lua_State* L, int index) {
|
|
||||||
std::string::size_type len;
|
|
||||||
auto str = lua_tolstring(L, index, &len);
|
|
||||||
return { str, len };
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline const char* get<const char*>(lua_State* L, int index) {
|
|
||||||
return lua_tostring(L, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
inline type get<type>(lua_State* L, int index) {
|
|
||||||
return static_cast<type>(lua_type(L, index));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -151,15 +153,16 @@ inline std::pair<T, int> get_user(lua_State* L, int index = 1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T pop(lua_State* L) {
|
auto pop(lua_State* L)
|
||||||
auto r = get<T>(L);
|
-> decltype(get<T>(L)) {
|
||||||
|
auto&& r = get<T>(L);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline EnableIf<std::is_arithmetic<T>> push(lua_State* L, T arithmetic) {
|
inline EnableIf<std::is_arithmetic<T>> push(lua_State* L, T arithmetic) {
|
||||||
detail::push_arithmetic(L, arithmetic, std::is_integral<T>{});
|
detail::push_arithmetic(std::is_integral<T>{}, L, arithmetic);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void push(lua_State*, reference& ref) {
|
inline void push(lua_State*, reference& ref) {
|
||||||
|
@ -245,7 +248,7 @@ inline auto ltr_get(lua_State*, int, F&& f, types<Args...>, types<>, Vs&&... vs)
|
||||||
}
|
}
|
||||||
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
|
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
|
||||||
inline auto ltr_get(lua_State* L, int index, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
|
inline auto ltr_get(lua_State* L, int index, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
|
||||||
return ltr_get(L, index + 1, std::forward<F>(f), t, types<Tail...>(), std::forward<Vs>(vs)..., get<Head>(L, index));
|
return ltr_get(L, index + 1, std::forward<F>(f), t, types<Tail...>(), std::forward<Vs>(vs)..., stack::get<Head>(L, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename... Vs, typename... Args>
|
template<typename F, typename... Vs, typename... Args>
|
||||||
|
@ -254,7 +257,7 @@ inline auto ltr_pop(lua_State*, F&& f, types<Args...>, types<>, Vs&&... vs) -> d
|
||||||
}
|
}
|
||||||
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
|
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
|
||||||
inline auto ltr_pop(lua_State* L, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
|
inline auto ltr_pop(lua_State* L, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
|
||||||
return ltr_pop(L, std::forward<F>(f), t, types<Tail...>(), std::forward<Vs>(vs)..., pop<Head>(L));
|
return ltr_pop(L, std::forward<F>(f), t, types<Tail...>(), std::forward<Vs>(vs)..., stack::pop<Head>(L));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename... Vs, typename... Args>
|
template<typename F, typename... Vs, typename... Args>
|
||||||
|
@ -263,7 +266,7 @@ inline auto rtl_pop(lua_State*, F&& f, types<Args...>, types<>, Vs&&... vs) -> d
|
||||||
}
|
}
|
||||||
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
|
template<typename F, typename Head, typename... Tail, typename... Vs, typename... Args>
|
||||||
inline auto rtl_pop(lua_State* L, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
|
inline auto rtl_pop(lua_State* L, F&& f, types<Args...> t, types<Head, Tail...>, Vs&&... vs) -> decltype(f(std::declval<Args>()...)) {
|
||||||
return rtl_pop(L, std::forward<F>(f), t, types<Tail...>(), pop<Head>(L), std::forward<Vs>(vs)...);
|
return rtl_pop(L, std::forward<F>(f), t, types<Tail...>(), stack::pop<Head>(L), std::forward<Vs>(vs)...);
|
||||||
}
|
}
|
||||||
} // detail
|
} // detail
|
||||||
|
|
||||||
|
@ -338,6 +341,12 @@ inline std::string dump_types(lua_State* L) {
|
||||||
}
|
}
|
||||||
return visual;
|
return visual;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct get_return {
|
||||||
|
typedef decltype(get<T>(nullptr)) type;
|
||||||
|
};
|
||||||
|
|
||||||
} // stack
|
} // stack
|
||||||
} // sol
|
} // sol
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args, typename... Keys>
|
template<typename... Args, typename... Keys>
|
||||||
typename return_type<Args...>::type get(Keys&&... keys) const {
|
auto get(Keys&&... keys) const
|
||||||
|
-> decltype(global.get(types<Args...>(), std::forward<Keys>(keys)...)) {
|
||||||
return global.get(types<Args...>(), std::forward<Keys>(keys)...);
|
return global.get(types<Args...>(), std::forward<Keys>(keys)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,40 +43,34 @@ T* get_ptr(T* val) {
|
||||||
class table : public reference {
|
class table : public reference {
|
||||||
friend class state;
|
friend class state;
|
||||||
template<typename T, typename U>
|
template<typename T, typename U>
|
||||||
T single_get(U&& key) const {
|
typename stack::get_return<T>::type single_get(U&& key) const {
|
||||||
push();
|
push();
|
||||||
stack::push(state(), std::forward<U>(key));
|
stack::push(state(), std::forward<U>(key));
|
||||||
lua_gettable(state(), -2);
|
lua_gettable(state(), -2);
|
||||||
type_assert(state(), -1, type_of<T>());
|
type_assert(state(), -1, type_of<T>());
|
||||||
auto result = stack::pop<T>(state());
|
auto&& result = stack::pop<T>(state());
|
||||||
lua_pop(state(), 1);
|
lua_pop(state(), 1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t I, typename Tup, typename... Ret>
|
template<std::size_t I, typename Tup, typename... Ret>
|
||||||
typename std::tuple_element<I, std::tuple<Ret...>>::type element_get(types<Ret...>, Tup&& key) const {
|
typename std::tuple_element<I, std::tuple<typename stack::get_return<Ret>::type...>>::type element_get(types<Ret...>, Tup&& key) const {
|
||||||
typedef typename std::tuple_element<I, std::tuple<Ret...>>::type T;
|
typedef typename std::tuple_element<I, std::tuple<Ret...>>::type T;
|
||||||
push();
|
return single_get<T>(std::get<I>(key));
|
||||||
stack::push(state(), std::get<I>(key));
|
|
||||||
lua_gettable(state(), -2);
|
|
||||||
type_assert(state(), -1, type_of<T>());
|
|
||||||
T result = stack::pop<T>(state());
|
|
||||||
lua_pop(state(), 1);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Tup, typename... Ret, std::size_t... I>
|
template<typename Tup, typename... Ret, std::size_t... I>
|
||||||
typename return_type<Ret...>::type tuple_get(types<Ret...> t, indices<I...>, Tup&& tup) const {
|
typename return_type<typename stack::get_return<Ret>::type...>::type tuple_get(types<Ret...> t, indices<I...>, Tup&& tup) const {
|
||||||
return std::make_tuple(element_get<I>(t, std::forward<Tup>(tup))...);
|
return std::make_tuple(element_get<I>(t, std::forward<Tup>(tup))...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Tup, typename Ret>
|
template<typename Tup, typename Ret>
|
||||||
Ret tuple_get(types<Ret> t, indices<0>, Tup&& tup) const {
|
typename stack::get_return<Ret>::type tuple_get(types<Ret> t, indices<0>, Tup&& tup) const {
|
||||||
return element_get<0>(t, std::forward<Tup>(tup));
|
return element_get<0>(t, std::forward<Tup>(tup));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ret, typename... Keys>
|
template<typename... Ret, typename... Keys>
|
||||||
typename return_type<Ret...>::type get(types<Ret...> t, Keys&&... keys) const {
|
typename return_type<typename stack::get_return<Ret>::type...>::type get(types<Ret...> t, Keys&&... keys) const {
|
||||||
static_assert(sizeof...(Keys) == sizeof...(Ret), "Must have same number of keys as return values");
|
static_assert(sizeof...(Keys) == sizeof...(Ret), "Must have same number of keys as return values");
|
||||||
return tuple_get(t, t, std::make_tuple(std::forward<Keys>(keys)...));
|
return tuple_get(t, t, std::make_tuple(std::forward<Keys>(keys)...));
|
||||||
}
|
}
|
||||||
|
@ -87,7 +81,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Ret, typename... Keys>
|
template<typename... Ret, typename... Keys>
|
||||||
typename return_type<Ret...>::type get(Keys&&... keys) const {
|
typename return_type<typename stack::get_return<Ret>::type...>::type get(Keys&&... keys) const {
|
||||||
return get(types<Ret...>(), std::forward<Keys>(keys)...);
|
return get(types<Ret...>(), std::forward<Keys>(keys)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,11 @@ struct return_type<> : types<>{
|
||||||
typedef void type;
|
typedef void type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Templ>
|
||||||
|
struct is_specialization_of : std::false_type { };
|
||||||
|
template <typename... T, template <typename...> class Templ>
|
||||||
|
struct is_specialization_of<Templ<T...>, Templ> : std::true_type { };
|
||||||
|
|
||||||
template<bool B>
|
template<bool B>
|
||||||
using Bool = std::integral_constant<bool, B>;
|
using Bool = std::integral_constant<bool, B>;
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,16 @@ inline type arithmetic(std::true_type) {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline type arithmetic(std::false_type) {
|
inline type arithmetic(std::false_type) {
|
||||||
|
return usertype<T>(is_specialization_of<T, userdata>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline type usertype(std::true_type) {
|
||||||
|
return type::userdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline type usertype(std::false_type) {
|
||||||
return type::none;
|
return type::none;
|
||||||
}
|
}
|
||||||
} // detail
|
} // detail
|
||||||
|
|
Loading…
Reference in New Issue
Block a user