#define LUA_LIB #include #include #include #include "lauxlib.h" #include "lua.h" // https://github.com/hongling0/lua-zset #define SKIPLIST_MAXLEVEL 32 #define SKIPLIST_P 0.25 typedef struct skipsetNode { int64_t obj; struct skipsetNode *backward; struct skiplistLevel { struct skipsetNode *forward; unsigned int span; } level[]; } skipsetNode; typedef struct skipset { struct skipsetNode *header, *tail; unsigned long length; int level; } skipset; static int slRandomLevel(void) { int level = 1; while ((random() & 0xffff) < (SKIPLIST_P * 0xffff)) level += 1; return (level < SKIPLIST_MAXLEVEL) ? level : SKIPLIST_MAXLEVEL; } static skipsetNode *slCreateNode(int level, int64_t obj) { skipsetNode *n = malloc(sizeof(*n) + level * sizeof(struct skiplistLevel)); n->obj = obj; return n; } static int slInsert(skipset *sl, int64_t obj) { skipsetNode *update[SKIPLIST_MAXLEVEL], *x; unsigned int rank[SKIPLIST_MAXLEVEL]; int i, level; x = sl->header; for (i = sl->level - 1; i >= 0; i--) { rank[i] = i == (sl->level - 1) ? 0 : rank[i + 1]; while (x->level[i].forward && x->level[i].forward->obj < obj) { rank[i] += x->level[i].span; x = x->level[i].forward; } update[i] = x; } x = x->level[0].forward; if (x && x->obj == obj) return 0; level = slRandomLevel(); if (level > sl->level) { for (i = sl->level; i < level; i++) { rank[i] = 0; update[i] = sl->header; update[i]->level[i].span = sl->length; } sl->level = level; } x = slCreateNode(level, obj); for (i = 0; i < level; i++) { x->level[i].forward = update[i]->level[i].forward; update[i]->level[i].forward = x; x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]); update[i]->level[i].span = (rank[0] - rank[i]) + 1; } for (i = level; i < sl->level; i++) { update[i]->level[i].span++; } x->backward = (update[0] == sl->header) ? NULL : update[0]; if (x->level[0].forward) x->level[0].forward->backward = x; else sl->tail = x; sl->length++; return 1; } static void slDeleteNode(skipset *sl, skipsetNode *x, skipsetNode **update) { int i; for (i = 0; i < sl->level; i++) { if (update[i]->level[i].forward == x) { update[i]->level[i].span += x->level[i].span - 1; update[i]->level[i].forward = x->level[i].forward; } else { update[i]->level[i].span -= 1; } } if (x->level[0].forward) { x->level[0].forward->backward = x->backward; } else { sl->tail = x->backward; } while (sl->level > 1 && sl->header->level[sl->level - 1].forward == NULL) sl->level--; sl->length--; } static void slFreeNode(skipsetNode *node) { free(node); } static int slDelete(skipset *sl, int64_t obj) { skipsetNode *update[SKIPLIST_MAXLEVEL], *x; int i; x = sl->header; for (i = sl->level - 1; i >= 0; i--) { while (x->level[i].forward && x->level[i].forward->obj < obj) x = x->level[i].forward; update[i] = x; } x = x->level[0].forward; if (x && (x->obj == obj)) { slDeleteNode(sl, x, update); slFreeNode(x); return 1; } else { return 0; /* not found */ } return 0; /* not found */ } static unsigned long slGetRank(skipset *sl, int64_t obj) { skipsetNode *x; unsigned long rank = 0; int i; x = sl->header; for (i = sl->level - 1; i >= 0; i--) { while (x->level[i].forward && x->level[i].forward->obj <= obj) { rank += x->level[i].span; x = x->level[i].forward; } if (x->obj && (x->obj == obj)) { return rank; } } return 0; } static skipsetNode *slGetNodeByRank(skipset *sl, unsigned long rank) { if (rank == 0 || rank > sl->length) return NULL; skipsetNode *x; unsigned long traversed = 0; int i; x = sl->header; for (i = sl->level - 1; i >= 0; i--) { while (x->level[i].forward && (traversed + x->level[i].span) <= rank) { traversed += x->level[i].span; x = x->level[i].forward; } if (traversed == rank) { return x; } } return NULL; } unsigned long slDeleteByRank(skipset *sl, unsigned int rank) { skipsetNode *update[SKIPLIST_MAXLEVEL], *x; unsigned long traversed = 0; int i; x = sl->header; for (i = sl->level - 1; i >= 0; i--) { while (x->level[i].forward && (traversed + x->level[i].span) < rank) { traversed += x->level[i].span; x = x->level[i].forward; } update[i] = x; } x = x->level[0].forward; if (x) { slDeleteNode(sl, x, update); slFreeNode(x); return 1; } return 0; } static skipset *slCreate(void) { int j; skipset *sl; sl = malloc(sizeof(*sl)); sl->level = 1; sl->length = 0; sl->header = slCreateNode(SKIPLIST_MAXLEVEL, 0); for (j = 0; j < SKIPLIST_MAXLEVEL; j++) { sl->header->level[j].forward = NULL; sl->header->level[j].span = 0; } sl->header->backward = NULL; sl->tail = NULL; return sl; } static void slFree(skipset *sl) { skipsetNode *node = sl->header->level[0].forward, *next; free(sl->header); while (node) { next = node->level[0].forward; slFreeNode(node); node = next; } free(sl); } static inline skipset * _to_skipset(lua_State *L, int idx) { skipset **sl = lua_touserdata(L, idx); if (sl == NULL) { luaL_error(L, "must be skipset object"); } return *sl; } static int _insert(lua_State *L) { skipset *sl = _to_skipset(L, 1); lua_Integer obj = luaL_checkinteger(L, 2); lua_pushboolean(L, slInsert(sl, obj)); return 1; } static int _delete(lua_State *L) { skipset *sl = _to_skipset(L, 1); lua_Integer obj = luaL_checkinteger(L, 2); lua_pushboolean(L, slDelete(sl, obj)); return 1; } static int _get_count(lua_State *L) { skipset *sl = _to_skipset(L, 1); lua_pushinteger(L, sl->length); return 1; } static int _get_rank(lua_State *L) { skipset *sl = _to_skipset(L, 1); lua_Integer obj = luaL_checkinteger(L, 2); unsigned long rank = slGetRank(sl, obj); if (rank == 0) { return 0; } lua_pushinteger(L, rank); return 1; } static int _get_by_rank(lua_State *L) { skipset *sl = _to_skipset(L, 1); unsigned long r1 = luaL_checkinteger(L, 2); skipsetNode *node = slGetNodeByRank(sl, r1); if (node) { lua_pushinteger(L, node->obj); return 1; } return 0; } static int _delete_by_rank(lua_State *L) { skipset *sl = _to_skipset(L, 1); unsigned int rank = luaL_checkinteger(L, 2); lua_pushinteger(L, slDeleteByRank(sl, rank)); return 1; } static int _new(lua_State *L) { skipset *psl = slCreate(); skipset **sl = (skipset **)lua_newuserdata(L, sizeof(skipset *)); *sl = psl; lua_pushvalue(L, lua_upvalueindex(1)); lua_setmetatable(L, -2); return 1; } static int _release(lua_State *L) { skipset *sl = _to_skipset(L, 1); slFree(sl); return 0; } LUAMOD_API int luaopen_skipset_c(lua_State *L) { luaL_checkversion(L); luaL_Reg l[] = { {"insert", _insert}, {"delete", _delete}, {"delete_byrank", _delete_by_rank}, {"count", _get_count}, {"rank", _get_rank}, {"byrank", _get_by_rank}, {NULL, NULL}}; lua_createtable(L, 0, 2); luaL_newlib(L, l); lua_setfield(L, -2, "__index"); lua_pushcfunction(L, _release); lua_setfield(L, -2, "__gc"); lua_pushcfunction(L, _get_count); lua_setfield(L, -2, "__len"); lua_pushcclosure(L, _new, 1); return 1; }