Skip to content

Instantly share code, notes, and snippets.

@CandyMi
Last active May 13, 2021 13:38
Show Gist options
  • Save CandyMi/411bdfd798998eaa675bc84b0fee9d45 to your computer and use it in GitHub Desktop.
Save CandyMi/411bdfd798998eaa675bc84b0fee9d45 to your computer and use it in GitHub Desktop.
Lua queue implemented with C API.
local queue = require "lqueue"
local q = queue:new()
-- local min, max = 1, 1
local min, max = 1, 10
for i = min, max do
q:push(string.char(math.random(97, 97 + 26)))
end
print("长度为: ", q:len())
print("pop :", q:pop())
for item, typename in q:next() do
print("Iteration:", item, typename, #item)
end
#define LUA_LIB
#include <core.h>
struct lua_queue_item {
int32_t ref; /* 在注册表的引用位置 */
struct lua_queue_item *next;
};
struct lua_queue {
int64_t cap;
struct lua_queue_item *head; /* 链表首部 */
struct lua_queue_item *tail; /* 链表尾部 */
};
/* 创建元素 */
static inline struct lua_queue_item* new_queue_item(void) {
struct lua_queue_item* q = xmalloc(sizeof(struct lua_queue_item));
if (!q)
return NULL;
/* 初始化数据结构属性 */
q->ref = LUA_NOREF; q->next = NULL;
return q;
}
/* 销毁元素 */
static inline void free_queue_item(struct lua_queue_item* q) {
xfree(q);
}
/* 插入一个元素到队列中 */
static int linsert(lua_State *L) {
struct lua_queue* q = luaL_testudata(L, 1, "__LUA_QUEUE__");
if (!q)
return luaL_error(L, "Need a lua_queue object but get other value (%s).", lua_typename(L, lua_type(L, 1)));
struct lua_queue_item* qitem = new_queue_item();
if (!qitem)
return luaL_error(L, "lua_queue Queue addition failed: out of memory.");
/* 插入并调整队列 */
if (!q->head) {
q->tail = q->head = qitem;
} else {
q->tail->next = qitem;
q->tail = qitem;
}
qitem->ref = luaL_ref(L, LUA_REGISTRYINDEX);
// 增加容量计数.
q->cap++;
return 0;
}
/* 从队列内取出一个元素 */
static int lremove(lua_State *L) {
struct lua_queue* q = luaL_testudata(L, 1, "__LUA_QUEUE__");
if (!q)
return luaL_error(L, "Need a lua_queue object but get other value (%s).", lua_typename(L, lua_type(L, 1)));
struct lua_queue_item* qitem = q->head;
if (!qitem)
return 0;
lua_rawgeti(L, LUA_REGISTRYINDEX, qitem->ref);
lua_pushstring(L, lua_typename(L, lua_type(L, -1)));
luaL_unref(L, LUA_REGISTRYINDEX, qitem->ref);
/* 删除并调整队列 */
if (qitem->next) {
q->head = qitem->next;
} else {
q->head = NULL;
q->tail = NULL;
}
q->cap--;
free_queue_item(qitem);
return 2;
}
/* 获取队列长度 */
static int llen(lua_State *L) {
struct lua_queue* q = luaL_testudata(L, 1, "__LUA_QUEUE__");
if (!q)
return luaL_error(L, "Need a lua_queue object but get othe value (%s).", lua_typename(L, lua_type(L, 1)));
lua_pushinteger(L, q->cap);
return 1;
}
/* 迭代器函数 */
static int lnext(lua_State *L) {
struct lua_queue* q = luaL_testudata(L, 1, "__LUA_QUEUE__");
if (!q)
return luaL_error(L, "Need a lua_queue object but get othe value (%s).", lua_typename(L, lua_type(L, 1)));
lua_pushcfunction(L, lremove);
lua_pushvalue(L, -2);
lua_pushinteger(L, 0);
return 3;
}
/* 触发gc后的动作 */
static int lgc(lua_State *L) {
struct lua_queue* q = luaL_testudata(L, 1, "__LUA_QUEUE__");
while (q->head != NULL) {
struct lua_queue_item* qitem = q->head;
struct lua_queue_item* qnext = q->head->next;
luaL_unref(L, LUA_REGISTRYINDEX, qitem->ref);
free_queue_item(qitem);
if (qnext)
q->head = qnext;
}
return 0;
}
/* 创建队列对象 */
static int lnew(lua_State *L) {
struct lua_queue* q = lua_newuserdata(L, sizeof(struct lua_queue));
if (!q)
return luaL_error(L, "lua_queue Failed to create object: out of memory.");
/* 初始化数据结构属性 */
q->cap = 0; q->head = NULL; q->tail = NULL;
/* 设置元表 */
luaL_setmetatable(L, "__LUA_QUEUE__");
return 1;
}
int luaopen_lqueue(lua_State *L) {
luaL_checkversion(L);
luaL_newmetatable(L, "__LUA_QUEUE__");
lua_pushstring (L, "__index");
lua_pushvalue(L, -2);
lua_rawset(L, -3);
lua_pushliteral(L, "__mode");
lua_pushliteral(L, "kv");
lua_rawset(L, -3);
lua_pushliteral(L, "version");
lua_pushnumber(L, 0.1);
lua_rawset(L, -3);
luaL_Reg queue_lib1[] = {
{"push", linsert},
{"pop", lremove},
{"next", lnext},
{"len", llen},
{"__gc", lgc},
{NULL, NULL},
};
luaL_setfuncs(L, queue_lib1, 0);
luaL_Reg queue_lib2[] = {
{"new", lnew},
{NULL, NULL},
};
luaL_newlib(L, queue_lib2);
lua_pushliteral(L, "version");
lua_pushnumber(L, 0.1);
lua_rawset(L, -3);
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment