distinction between "light user data" "user data" and "upvalue", as they are not the same thing

a lua upvalue can be lightuserdata, userdata, or anything else that can have its address taken (it's immediately popped of the stack and carted around with function call)
a lightuserdata can only be a pointer (void*)
a regular userdata can be anything, but is stored as void* because of "anything" semantics and C heritage of lua
upvalues deserve to use the `lua_upvalueindex(n)` macro: lightuserdata/userdata does not (must not) go through this process
This commit is contained in:
PrincessNyanara 2014-06-07 00:24:48 -04:00 committed by Rapptz
parent 77901bb654
commit 736d354861
4 changed files with 63 additions and 11 deletions

View File

@ -25,8 +25,10 @@
#include "reference.hpp"
#include "tuple.hpp"
#include "stack.hpp"
#include "function_types.hpp"
#include <cstdint>
#include <functional>
#include <memory>
namespace sol {
class function : public reference {
@ -133,7 +135,7 @@ struct pusher<function_t> {
// We don't need to store the size, because the other side is templated
// with the same member function pointer type
Decay<TFx> fxptr(std::forward<TFx>(fx));
void* userobjdata = static_cast<void*>(detail::get_ptr(obj));
void* userobjdata = static_cast<void*>(sol::detail::get_ptr(obj));
lua_CFunction freefunc = &static_member_function<Decay<TObj>, TFx>::call;
const char* freefuncname = fkey.c_str();
const luaL_Reg funcreg[2] = {
@ -210,7 +212,29 @@ struct pusher<function_t> {
};
template <typename Signature>
struct pusher<std::function<Signature>> {
typedef std::function<Signature> fx_t;
static void push_fx(lua_State* L, std::unique_ptr<base_function> luafunc) {
auto&& metakey = userdata_traits<fx_t>::metatable;
const char* metatablename = std::addressof(metakey[0]);
base_function* target = luafunc.release();
void* userdata = reinterpret_cast<void*>(target);
lua_CFunction freefunc = &base_function::call;
if (luaL_newmetatable(L, metatablename) == 1) {
lua_pushstring(L, "__gc");
lua_pushcclosure(L, &base_function::gc, 0);
lua_settable(L, -3);
}
stack::detail::push_userdata(L, userdata, metatablename);
lua_pushcclosure(L, freefunc, 1);
}
static void push(lua_State* L, std::function<Signature> fx) {
std::unique_ptr<base_function> sptr(new functor_function<fx_t>(std::move(fx)));
push_fx(L, std::move(sptr));
}
};
template <typename Signature>

View File

@ -167,7 +167,7 @@ struct base_function {
}
static int call(lua_State* L) {
void** pinheritancedata = static_cast<void**>(stack::get<lightuserdata_t>(L, 1).value);
void** pinheritancedata = static_cast<void**>(stack::get<upvalue_t>(L, 1).value);
return base_call(L, *pinheritancedata);
}

View File

@ -47,11 +47,10 @@ T* get_ptr(T* val) {
namespace stack {
namespace detail {
template<typename T, typename Key>
template<typename T, typename Key, typename U = Unqualified<T>>
inline void push_userdata(lua_State* L, T&& userdata, Key&& metatablekey) {
T* pdatum = static_cast<T*>(lua_newuserdata(L, sizeof(T)));
T& datum = *pdatum;
datum = std::forward<T>(userdata);
U* pdatum = static_cast<U*>(lua_newuserdata(L, sizeof(U)));
new(pdatum)U(std::forward<T>(userdata));
luaL_getmetatable(L, std::addressof(metatablekey[0]));
lua_setmetatable(L, -2);
}
@ -149,6 +148,13 @@ struct getter<userdata_t> {
template <>
struct getter<lightuserdata_t> {
lightuserdata_t get(lua_State* L, int index = 1) {
return{ lua_touserdata(L, index) };
}
};
template <>
struct getter<upvalue_t> {
upvalue_t get(lua_State* L, int index = 1) {
return{ lua_touserdata(L, lua_upvalueindex(index)) };
}
};
@ -216,8 +222,8 @@ struct pusher<nil_t> {
template<>
struct pusher<lua_CFunction> {
static void push(lua_State* L, lua_CFunction func) {
lua_pushcfunction(L, func);
static void push(lua_State* L, lua_CFunction func, int n = 0) {
lua_pushcclosure(L, func, n);
}
};
@ -228,6 +234,13 @@ struct pusher<void*> {
}
};
template<>
struct pusher<upvalue_t> {
static void push(lua_State* L, upvalue_t upvalue) {
lua_pushlightuserdata(L, upvalue);
}
};
template<>
struct pusher<lightuserdata_t> {
static void push(lua_State* L, lightuserdata_t userdata) {
@ -235,6 +248,15 @@ struct pusher<lightuserdata_t> {
}
};
template<>
struct pusher<userdata_t> {
template <typename T, typename U = Unqualified<T>>
static void push(lua_State* L, T&& data) {
U* userdata = static_cast<U*>(lua_newuserdata(L, sizeof(U)));
new(userdata)U(std::forward<T>(data));
}
};
template<>
struct pusher<const char*> {
static void push(lua_State* L, const char* str) {
@ -293,7 +315,7 @@ inline int push_as_upvalues(lua_State* L, T& item) {
data_t data{{}};
std::memcpy(std::addressof(data[0]), std::addressof(item), itemsize);
for (auto&& v : data) {
push(L, v);
push(L, upvalue_t(v));
}
return data_t_count;
}
@ -304,7 +326,7 @@ inline std::pair<T, int> get_as_upvalues(lua_State* L, int index = 1) {
typedef std::array<void*, data_t_count> data_t;
data_t voiddata{ {} };
for (std::size_t i = 0, d = 0; d < sizeof(T); ++i, d += sizeof(void*)) {
voiddata[ i ] = get<lightuserdata_t>(L, index++);
voiddata[ i ] = get<upvalue_t>(L, index++);
}
return std::pair<T, int>(*reinterpret_cast<T*>(static_cast<void*>(voiddata.data())), index);
}

View File

@ -32,7 +32,13 @@ const nil_t nil {};
struct void_type {};
const void_type Void {};
struct function_t {};
struct lightuserdata_t {
struct upvalue_t {
void* value;
upvalue_t(void* data) : value(data) {}
operator void* () const { return value; }
};
struct lightuserdata_t {
void* value;
lightuserdata_t(void* data) : value(data) {}
operator void* () const { return value; }