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:
ThePhD 2014-05-09 10:48:55 -04:00
parent d7ea4718c8
commit ff7326ed96
6 changed files with 106 additions and 87 deletions

View File

@ -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

View File

@ -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)...);
} }

View File

@ -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)...);
} }

View File

@ -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>;

View File

@ -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