/* lua程序设计 28.2 Metatables 程序范例*/
extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}
#include <iostream>
using namespace std;
#pragma comment(lib,"E:\\luaSRC\\lua5.1\\lib\\static\\lua5.1.lib")
typedef struct NumArray
{
int size;
double values[1]; /* variable part */
} NumArray;
static NumArray *checkarray (lua_State *checkarray_L)
{
//luaL_checkudata检查在栈中指定位置的对象是否为带有给定名字的metatable的usertatum。
//如果对象不存在正确的metatable,返回NULL(或者它不是一个userdata);
//否则,返回userdata的地址。
void *ud = luaL_checkudata(checkarray_L, 1, "LuaBook.array");
luaL_argcheck(checkarray_L, ud != NULL, 1, "`array' expected");
return (NumArray *)ud;
}
static int getsize (lua_State *getsize_L)
{
NumArray *a = checkarray(getsize_L);
lua_pushnumber(getsize_L, a->size);
return 1;
}
static double *getelem (lua_State *getelem_L)
{
NumArray *a = checkarray(getelem_L);
int index = luaL_checkint(getelem_L, 2);
luaL_argcheck(getelem_L, 1 <= index && index <= a->size, 2, "index out of range");
/* return element address */
return &a->values[index - 1];
}
static int setarray (lua_State *setarray_L)
{
double newvalue = luaL_checknumber(setarray_L, 3);
*getelem(setarray_L) = newvalue;
return 0;
}
static int getarray (lua_State *getarray_L) {
lua_pushnumber(getarray_L, *getelem(getarray_L));
return 1;
}
static int newarray (lua_State *newarray_L)
{
int n = luaL_checkint(newarray_L, 1);
//由于原始的结构中已经包含了一个元素的空间,所以我们从n 中减去 1
size_t nbytes = sizeof(NumArray) + (n - 1)*sizeof(double);
//调用lua_newuserdata分配指定的大小空间,并压入栈中作为返回值
NumArray *a = (NumArray *)lua_newuserdata(newarray_L, nbytes);
//将元表压栈
luaL_getmetatable(newarray_L, "LuaBook.array");//luaL_getmetatable函数获取registry中的tname对应的metatable。 并压入栈
lua_setmetatable(newarray_L, -2);//将刚刚压栈位置-1的元表 放入-2位置的userdata中设为该userdata的元表(元表就在userdata里面了) 并在栈中消除元表
//lua_setmetatable把一个 table 弹出堆栈,并将其设为给定索引处的值的 metatable 。
//设置size大小
a->size = n;
//分配的内存已经在栈中
return 1; /* new userdatum is already on the stack */
}
static const struct luaL_reg arraylib [] =
{
{"new", newarray},
{"set", setarray},
{"get", getarray},
{"size", getsize},
{NULL, NULL}
};
//新 userdata元表版本
int luaopen_array (lua_State *L)
{
//luaL_newmetatable函数创建一个新表(将用作metatable),将新表放到栈顶并建立表和registry中类型名的联系。
//这个关联是双向的:使用类型名作为表的key;
//同时使用表作为类型名的key(这种双向的关联,使得其他的两个函数的实现效率更高)。
luaL_newmetatable(L, "LuaBook.array");
luaL_openlib(L, "array", arraylib, 0);
return 1;
}
/*
1.lua
a = array.new(1000)
print(a) --> userdata: 0x8064d48
print(array.size(a)) --> 1000
for i=1,1000 do
array.set(a, i, 1/i)
end
print(array.get(a, 10)) --> 0.1
*/
void main()
{
lua_State* L = luaL_newstate();
luaL_openlibs(L);
luaopen_array(L);
int r = luaL_dofile(L,"1.lua");
lua_close(L);
}
lua程序设计 28.2 Metatables userdata程序范例
最新推荐文章于 2022-04-11 18:35:32 发布