希望 Lua 可以增加一个新特性 userdata slice
Lua 是一门嵌入式语言,和 host 的联动非常重要。Lua 使用 userdata 来保存 host 里的数据,userdata 非常强大,可以有 metatable 还可以关联一个 uservalue ,可以封装一切 C/C++ 对象,非常强大。但有的时候却稍显不足,似乎缺了点什么,导致一些简单的需求要用很繁琐的方式解决。
有个想法想过很久,今天动了念头用英文写了一遍投递到 lua 邮件列表里去了。
那就是,如果我们可以给 userdata 的值关联一个整数,而不是把 uservalue 关联到 userdata 的对象里那样,可以简化很多事情。
看这样一个例子:
如果我们有一个数据结构:
struct foo { struct foo1 foo1; struct foo2 *foo2; };
如何保存到 lua 里被 lua 引用呢?通常我们使用一个 userdata 封装它:
struct foo * f = lua_newuserdata(L, sizeof(*f));
但是,如果我们想进一步引用这个结构中的一个子结构怎么办?即,如果我们在 lua 里有了 userdata foo, 希望可以通过 foo.foo1 引用其子结构 foo1, 用 foo.foo2 引用 foo2 怎么办?
当然,我们先要给 foo 配置一个 metatable 并实现 index 元方法。这样在语法上就可以用 foo.foo1 和 foo.foo2 了。
但是 foo.foo1 和 foo.foo2 导致是什么?在目前的 lua 中,必须也返回一个 userdata 。那么我们就得在 foo.foo1 时,生成一个新的 userdata 作为 proxy 来访问 foo 对象的一部分。而且一旦访问过 foo.foo1 还得 cache 住这个新生成的 userdata ,保证下次再引用时还能返回同一个 userdata 。
为了保证 foo 和 foo.foo1 的生命期绑定,也就是在 foo.foo1 还在用的时候 foo 不被回收掉,往往我们还需要在 foo.foo1 的 uservalue 中保存一份 foo 的引用。这样才可以让 gc 能正确工作。
如果我们可以给 userdata 的值(而不是 object)关联一个整数就不一样了。例如,我们用 0 表示 foo 本身,1 表示 foo.foo1 ,2 表示 foo.foo2 。当 foo 被创建出来的时候,关联值默认是 0 ,也就是指代 foo 本身。
当我们运行到 foo.foo1 时,在 index 元方法中可以返回同一个 foo userdata ,但关联上新值 1 。注意,这个 1 是跟着返回值走的,并不在 userdata object 上,所以并不影响之前的 foo 对象。
这样,同一个 foo userdata 就有了对 C 对象的多种表达,在 lua 中也可以正常的做比较,做 table 的键。
为了实现这个新特性,并不需要修改 lua 原有的定义,也不需要增加新类型。只需要把以前类型为 LUA_TUSERDATA
的值在实现上变成两个整数组。第一个整数是一个 userdata 的 handle ,而所有真正的 userdata object 指针都保存在 lua vm 的 global state 里即可。第二个整数是关联其上的 slice 值,表示这个值应用 userdata object 的哪一个切片。
这一对值可以随 lua 的赋值质量做值拷贝,而不像之前的 userdata 只是做引用拷贝,这样就可以作到对同一个 C 对象的不同表达。
我们只需要增加两个新的 C API 就够了:
int lua_getuserslice(lua_State *L, int index); void lua_setuserslice(lua_State *L, int index, int slice);
和 lua_getuservalue
的用法也基本一致。
有了这个特性,封装 GUI 对象或 3d engine 中的对象要容易的多。
当我们在 lua 里写 OBJECT 和 OBJECT.X 或 OBJECT.X.Y 时,它们可以都指向同一个 userdata object ,只是 slice 不同。这样 OBJECT.X 获得 OBJECT 下的一个子节点也就轻量的多了。
Comments
Posted by: Jonine | (8) January 8, 2019 02:08 PM
Posted by: blues1021 | (7) June 11, 2018 10:53 PM
Posted by: louis | (6) November 17, 2015 05:19 PM
Posted by: cooldesert | (5) August 24, 2015 10:33 AM
Posted by: Cloud | (4) August 21, 2015 07:59 PM
Posted by: wks | (3) August 21, 2015 08:45 AM
Posted by: 陈冠希 | (2) August 20, 2015 10:25 AM
Posted by: Anonymous | (1) August 19, 2015 05:25 PM