lua程序设计 28.2 Metatables userdata程序范例

/* 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);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值