lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On 19 August 2015 at 13:18, 云风 Cloud Wu <cloudwu@gmail.com> wrote:
> Lua is a embedded language, it uses powerful userdata to wrap the c object
> as the lua object. But sometimes it's not enough.
>
> For example, if we have a C struct like this :
>
> struct foo {
>   struct foo1 foo1;
>   struct foo2 *foo2;
> };
>
> We can use userdata to store struct foo in lua variables :
>
> struct foo * f = lua_newuserdata(L, sizeof(*f));
>
> How to reference sub struct foo1/foo2 in lua ? maybe we can give the
> userdata a metatable, implementing an __index metamethod.
>
> But foo.foo1 or foo.foo2 should be a new userdata. It needs more complex and
> expensive way :
>
> Creating a proxy userdata to access a part of struct foo, put the reference
> of proxy userdata in uservalue of userdata foo to prevent collecting foo
> before foo1/foo2 proxy, etc.
>
> So I suggest introduce a new mechanism of userdata to simplify them. I call
> it userdata slice (maybe it's not a good name).
>
> If we can associate an integer to the userdata value, the userdata whould be
> more flexible. It is different from uservalue, because uservalue is in
> userdata object, not in value.
>
> An userdata object has only one uservalue , but each userdata value can has
> an unique associated integer.
>
> Two C API needed:
>
> int lua_getuserslice(lua_State *L, int index);
> void lua_setuserslice(lua_State *L, int index, int slice);

You're saying the slice offset would be stored in the userdata itself?
This would imply that setting a slice would mutate the userdata object?

If not, your slice still needs to create an extra object,
in which case, how is this better than the uservalue option?
i.e.

void makeslice(lua_State *L, int idx, ssize_t offset) {
    idx = lua_absindex(L, idx);
    ssize_t* slice = lua_newuserdata(L, sizeof(ssize_t));
    *slice = offset;
    lua_pushvalue(L, idx);
    lua_setuservalue(L, -2);
}
void* getslice(lua_State *L, int idx) {
    ssize_t offset = *(ssize_t*)lua_touserdata(L, idx);
    void* udata = lua_touserdata(L, lua_getuservalue(L, idx));
    return udata+offset;
}

You would also need to add argument checking to the above.
But you *still* need to add metamethods to these objects.
e.g. You have a slice, but you need to define a getter/setters for the
struct components.
At which point, you might as well write a 'slice' customised for your
needs, as there won't be a general one-size-fits-all solution.

> Any value with type LUA_TUSERDATA in lua is an two 32bit integer tuple ( or
> two 16bit integer for small lua), one is the userdata (32bit int) handle ,
> another is the associated integer.
>
> Using handle instead of really address of userdata object because we can put
> two 32bit integer in 64bit lua value.
>
> I think it's easy to implement and keep the c api compatibility with the
> previous version.

I'm not sure how this would work?
You need 64bits to store a userdata address on a 64 bit architecture.

> Storing C/C++ objects in GUI or 3d engines could be more simple : OBJECT.X
> and OBJECT.X.Y can be the same userdata with OBJECT without creating new
> userdata, only the slice is different.

But you would still need a different object.