You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
4.9 KiB
C
223 lines
4.9 KiB
C
/*
|
|
* author: xjdrew
|
|
* date: 2014-06-03 20:38
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "lua.h"
|
|
#include "lauxlib.h"
|
|
#include "skiplist.h"
|
|
|
|
static inline skiplist*
|
|
_to_skiplist(lua_State *L) {
|
|
skiplist **sl = lua_touserdata(L, 1);
|
|
if(sl==NULL) {
|
|
luaL_error(L, "must be skiplist object");
|
|
}
|
|
return *sl;
|
|
}
|
|
|
|
static int
|
|
_insert(lua_State *L) {
|
|
skiplist *sl = _to_skiplist(L);
|
|
double score = luaL_checknumber(L, 2);
|
|
luaL_checktype(L, 3, LUA_TSTRING);
|
|
size_t len;
|
|
const char* ptr = lua_tolstring(L, 3, &len);
|
|
slobj *obj = slCreateObj(ptr, len);
|
|
slInsert(sl, score, obj);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_delete(lua_State *L) {
|
|
skiplist *sl = _to_skiplist(L);
|
|
double score = luaL_checknumber(L, 2);
|
|
luaL_checktype(L, 3, LUA_TSTRING);
|
|
slobj obj;
|
|
obj.ptr = (char *)lua_tolstring(L, 3, &obj.length);
|
|
lua_pushboolean(L, slDelete(sl, score, &obj));
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
_delete_rank_cb(void* ud, slobj *obj) {
|
|
lua_State *L = (lua_State*)ud;
|
|
lua_pushvalue(L, 4);
|
|
lua_pushlstring(L, obj->ptr, obj->length);
|
|
lua_call(L, 1, 0);
|
|
}
|
|
|
|
static int
|
|
_delete_by_rank(lua_State *L) {
|
|
skiplist *sl = _to_skiplist(L);
|
|
unsigned int start = luaL_checkinteger(L, 2);
|
|
unsigned int end = luaL_checkinteger(L, 3);
|
|
luaL_checktype(L, 4, LUA_TFUNCTION);
|
|
if (start > end) {
|
|
unsigned int tmp = start;
|
|
start = end;
|
|
end = tmp;
|
|
}
|
|
|
|
lua_pushinteger(L, slDeleteByRank(sl, start, end, _delete_rank_cb, L));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_get_count(lua_State *L) {
|
|
skiplist *sl = _to_skiplist(L);
|
|
lua_pushinteger(L, sl->length);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_get_rank(lua_State *L) {
|
|
skiplist *sl = _to_skiplist(L);
|
|
double score = luaL_checknumber(L, 2);
|
|
luaL_checktype(L, 3, LUA_TSTRING);
|
|
slobj obj;
|
|
obj.ptr = (char *)lua_tolstring(L, 3, &obj.length);
|
|
|
|
unsigned long rank = slGetRank(sl, score, &obj);
|
|
if(rank == 0) {
|
|
return 0;
|
|
}
|
|
|
|
lua_pushinteger(L, rank);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_get_rank_range(lua_State *L) {
|
|
skiplist *sl = _to_skiplist(L);
|
|
unsigned long r1 = luaL_checkinteger(L, 2);
|
|
unsigned long r2 = luaL_checkinteger(L, 3);
|
|
int reverse, rangelen;
|
|
if(r1 <= r2) {
|
|
reverse = 0;
|
|
rangelen = r2 - r1 + 1;
|
|
} else {
|
|
reverse = 1;
|
|
rangelen = r1 - r2 + 1;
|
|
}
|
|
|
|
skiplistNode* node = slGetNodeByRank(sl, r1);
|
|
lua_createtable(L, rangelen, 0);
|
|
int n = 0;
|
|
while(node && n < rangelen) {
|
|
n++;
|
|
|
|
lua_pushlstring(L, node->obj->ptr, node->obj->length);
|
|
lua_rawseti(L, -2, n);
|
|
node = reverse? node->backward : node->level[0].forward;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_get_score_range(lua_State *L) {
|
|
skiplist *sl = _to_skiplist(L);
|
|
double s1 = luaL_checknumber(L, 2);
|
|
double s2 = luaL_checknumber(L, 3);
|
|
int reverse;
|
|
skiplistNode *node;
|
|
|
|
if(s1 <= s2) {
|
|
reverse = 0;
|
|
node = slFirstInRange(sl, s1, s2);
|
|
} else {
|
|
reverse = 1;
|
|
node = slLastInRange(sl, s2, s1);
|
|
}
|
|
|
|
lua_newtable(L);
|
|
int n = 0;
|
|
while(node) {
|
|
if(reverse) {
|
|
if(node->score < s2) break;
|
|
} else {
|
|
if(node->score > s2) break;
|
|
}
|
|
n++;
|
|
|
|
lua_pushlstring(L, node->obj->ptr, node->obj->length);
|
|
lua_rawseti(L, -2, n);
|
|
|
|
node = reverse? node->backward:node->level[0].forward;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_get_member_by_rank(lua_State *L){
|
|
skiplist *sl = _to_skiplist(L);
|
|
unsigned long r = luaL_checkinteger(L, 2);
|
|
skiplistNode *node = slGetNodeByRank(sl, r);
|
|
if (node) {
|
|
lua_pushlstring(L, node->obj->ptr, node->obj->length);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_dump(lua_State *L) {
|
|
skiplist *sl = _to_skiplist(L);
|
|
slDump(sl);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
_new(lua_State *L) {
|
|
skiplist *psl = slCreate();
|
|
|
|
skiplist **sl = (skiplist**) lua_newuserdata(L, sizeof(skiplist*));
|
|
*sl = psl;
|
|
lua_pushvalue(L, lua_upvalueindex(1));
|
|
lua_setmetatable(L, -2);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
_release(lua_State *L) {
|
|
skiplist *sl = _to_skiplist(L);
|
|
printf("collect sl:%p\n", sl);
|
|
slFree(sl);
|
|
return 0;
|
|
}
|
|
|
|
int luaopen_skiplist_c(lua_State *L) {
|
|
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM > 501
|
|
luaL_checkversion(L);
|
|
#endif
|
|
|
|
luaL_Reg l[] = {
|
|
{"insert", _insert},
|
|
{"delete", _delete},
|
|
{"delete_by_rank", _delete_by_rank},
|
|
|
|
{"get_count", _get_count},
|
|
{"get_rank", _get_rank},
|
|
{"get_rank_range", _get_rank_range},
|
|
{"get_score_range", _get_score_range},
|
|
{"get_member_by_rank", _get_member_by_rank},
|
|
|
|
{"dump", _dump},
|
|
{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_pushcclosure(L, _new, 1);
|
|
return 1;
|
|
}
|