云风的个人空间 : 为Lua扩展一个循环队列[LuaQueue]

首页 :: 索引 :: 修订历史 :: 你好, 18.222.78.65
你的足迹: » 为Lua扩展一个循环队列
这是一个旧版本的LuaQueue于2006-09-21 13:36:13.
这里展示用 lua 的 cclosure 扩展的一个技巧,实现了一个 lua 的循环队列:


struct queue_data {
	int size;
	int head;
	int tail;
};
 
/* 
    当传入一个非 nil 的 lua 对象时,这个对象将进入队列。返回 true 表示成功,否则队列满
    当不传参数时,把队首元素出队列并返回出去;返回空表示队列空
 */
static int queue(lua_State *L)
{
	struct queue_data *qd=(struct queue_data*)g_api->lua_touserdata(L,lua_upvalueindex(1));
	if (g_api->lua_gettop(L)==0) {
		// queue leave
		if (qd->head==qd->tail) {
			return 0;
		}
		g_api->lua_pushvalue(L,lua_upvalueindex(qd->head));
		g_api->lua_pushnil(L);
		g_api->lua_replace(L,lua_upvalueindex(qd->head));
		++qd->head;
		if (qd->head > qd->size) {
			qd->head=2;
		}
		return 1;
	}
	else {
		// queue enter
		int tail=qd->tail+1;
		if (tail>qd->size) {
			tail=2;
		}
		if (tail==qd->head) {
			// queue overflow
			return 0;
		}
		g_api->lua_settop(L,1);
		g_api->lua_replace(L,lua_upvalueindex(qd->tail));
		qd->tail=tail;
		g_api->lua_pushboolean(L,true);
		return 1;
	}
}
 
/* 创建一个尺寸为 size 的队列对象并返回,size 收到 upvalue 数量限制,这里最大可以为 253 */
int queue_create(lua_State *L)
{
	struct queue_data *qd;
	g_api->lua_settop(L,1);
	int size=g_api->lua_tointeger(L,1)+2;
	if (size>253 || !g_api->lua_checkstack(L,size)) {
		return 0;
	}
	g_api->lua_settop(L,0);
	qd=(struct queue_data*)g_api->lua_newuserdata(L,sizeof(struct queue_data));
	qd->size=size;
	qd->head=qd->tail=2;
	g_api->lua_settop(L,size);
	g_api->lua_pushcclosure(L,queue,size);
	g_api->lua_pushvalue(L,-1);
	g_confirm_closure=g_api->lua_ref(L);
	return 1;
}