├── Makefile ├── README.md ├── lua-bind ├── benchmark.lua ├── example.lua ├── lskiplist.c └── test.lua ├── src ├── skiplist.c └── skiplist.h └── test └── main.c /Makefile: -------------------------------------------------------------------------------- 1 | PLATFORM=$(shell uname) 2 | CC = gcc 3 | 4 | DEBUG_FLAG = -O3 5 | CFLAGS = -c $(DEBUG_FLAG) -Wall -Werror=declaration-after-statement -std=c89 -pedantic -fPIC 6 | LIBS = 7 | LDFLAGS = $(DEBUG_FLAG) -Wall $(LIBS) 8 | 9 | BIN = test/test 10 | TEST_OBJS = test/main.o src/skiplist.o 11 | LUALIB_OBJS = src/skiplist.o lua-bind/lskiplist.o 12 | 13 | SOLIB = lua-bind/lskiplist.so 14 | 15 | all : $(BIN) 16 | 17 | lua : $(SOLIB) 18 | 19 | $(BIN): $(TEST_OBJS) 20 | $(CC) -o $@ $^ $(LDFLAGS) 21 | 22 | $(TEST_OBJS) : %.o : %.c 23 | $(CC) -o $@ $(CFLAGS) $< -I./src 24 | 25 | $(SOLIB) : $(LUALIB_OBJS) 26 | $(CC) -o $@ $^ --shared -dynamiclib -Wl,-undefined,dynamic_lookup 27 | 28 | lua-bind/lskiplist.o : lua-bind/lskiplist.c | src/skiplist.h 29 | $(CC) -o $@ $(CFLAGS) $< -I./src 30 | 31 | clean : 32 | rm -f $(TEST_OBJS) $(BIN) $(LUALIB_OBJS) $(SOLIB) 33 | 34 | .PHONY : clean 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # skiplist 2 | 3 | ## Description 4 | 5 | [skiplist](https://en.wikipedia.org/wiki/Skip_list) is a data structure that allows fast search within an ordered sequence of elements. Fast search is made possible by maintaining a linked hierarchy of subsequences, with each successive subsequence skipping over fewer elements than the previous one. Searching starts in the sparsest subsequence until two consecutive elements have been found, one smaller and one larger than or equal to the element searched for. Via the linked hierarchy, these two elements link to elements of the next sparsest subsequence, where searching is continued until finally we are searching in the full sequence. The elements that are skipped over may be chosen probabilistically or deterministically, with the former being more common. 6 | 7 | ## Features 8 | use score or your own function to compare elems 9 | 10 | ## VS 11 | ### skiplist VS qsort 12 | skiplist takes 5x times as qsort; 13 | 14 | 2x space as array (qsort); 15 | 16 | ### skiplist VS RBTree(Red-black Tree) 17 | insert, delete, search : both O(logN) 18 | 19 | skiplist takes a little more space than RBTree, 20 | but offers a feature with *rank of elem* with O(logN) 21 | 22 | ## Space and Time 23 | space : O(N) 24 | 25 | search one: O(logN) 26 | 27 | search range [min, max]: O(logN + max - min) 28 | 29 | get rank of data: O(logN) 30 | 31 | insert one: O(logN) 32 | 33 | delete one: O(logN) 34 | 35 | see [zset in redis](https://github.com/antirez/redis/blob/3.0/src/t_zset.c) 36 | 37 | ## Benchmark 38 | 39 | macOS 2.5GHz Intel Core i5 40 | 41 | insert 1000k 1.2 seconds 42 | 43 | search random 1000k 0.3 seconds 44 | 45 | ## API for C 46 | 47 | ### int slRandomLevel(); 48 | 49 | ### slNode_t * slCreateNode(int level, void *udata, double score); 50 | ### void slFreeNode(slNode_t *node, slFreeCb freeCb, void *ctx); 51 | 52 | ### void slInit(sl_t *sl); 53 | you can use slInit to init a struct pointer by yourself 54 | 55 | ### void slDestroy(sl_t *sl, slFreeCb freeCb, void *ctx); 56 | just free every node inside of sl, do not free sl; 57 | 58 | ### sl_t *slCreate(); 59 | alloc and init sl; 60 | 61 | ### void slFree(sl_t *sl, slFreeCb freeCb, void *ctx); 62 | slDestroy and free sl; 63 | 64 | ### slCompareCb slSetCompareCb(sl_t *sl, slCompareCb comp); 65 | set your own comp function 66 | 67 | ### void slInsertNode(sl_t *sl, slNode_t *node, void *ctx); 68 | ctx would be passed to sl->comp function 69 | 70 | ### int slGetRank(sl_t *sl, slNode_t *node, void *ctx); 71 | rank of the node; 72 | 73 | ctx would be passed to sl->comp function 74 | 75 | 76 | ### int slGetSize(sl_t *sl); 77 | size of sl 78 | 79 | ### slNode_t * slGetNodeByRank(sl_t *sl, int rank); 80 | 81 | ### int slDeleteNode(sl_t *sl, slNode_t *node, void *ctx, slNode_t **pNode); 82 | delete node; 83 | 84 | return 0 if succeed; 85 | 86 | call slFreeNode(node) if pNode == NULL and if node found in sl; 87 | 88 | write &node to pNode if pNode != NULL and if node found in sl, 89 | 90 | you should call slFreeNode by yourself; 91 | 92 | 93 | ### slDeleteByRank(sl, rank, freeCb, ctx) 94 | 95 | ### int slDeleteByRankRange(sl_t *sl, int rankMin, int rankMax, slFreeCb freeCb, void *ctx); 96 | delete rank range [rankMin, rankMax]; 97 | 98 | return deleted count; 99 | 100 | ctx would be passed to sl->comp function; 101 | 102 | ### slNode_t * slFirstGEThan(sl_t *sl, double score); 103 | greater or equal than score; 104 | 105 | 106 | ### slNode_t * slLastLEThan(sl_t *sl, double score); 107 | less or equal than score; 108 | 109 | ## lua-bind 110 | 111 | see [example](lua-bind/example.lua) 112 | 113 | see [test](lua-bind/test.lua) 114 | 115 | see [benchemark](lua-bind/benchmark.lua) 116 | 117 | ## Benchmark for lua-bind 118 | 119 | on macOS sierra 10.12.2, macbook Mid-2012, 2.5GHz Intel Core i5 120 | 121 | 122 | ### with default compare function, compare with score 123 | 124 | ``` 125 | insert, create() size=100000, time=0.16715 126 | update, sl:size() == 100000, update cnt=100000 time=0.13545 127 | rank_range sl:size() == 100000,cnt=100000(x, x+50) time=0.92219 128 | rank_of sl:size() == 100000,cnt=100000,time=0.14065 129 | get_by_rank sl:size() == 100000,cnt=100000,time=0.11291 130 | delete sl:size() == 100000,cnt=100000,time=0.13143 131 | ``` 132 | 133 | ### with custom compare function 134 | ``` 135 | insert, create() size=100000, time=0.97777 136 | update, sl:size() == 100000, update cnt=100000 time=1.86796 137 | rank_range sl:size() == 100000,cnt=100000(x, x+50) time=1.14272 138 | rank_of sl:size() == 100000,cnt=100000,time=1.31014 139 | get_by_rank sl:size() == 100000,cnt=100000,time=0.13249 140 | delete sl:size() == 100000,cnt=100000,time=0.96182 141 | ``` 142 | 143 | ## API for Lua 144 | 145 | ### lskiplist.new(comp_func) 146 | create a skiplist 147 | if comp_func is nil or boolean var, skiplist would compare with score 148 | ``` 149 | example: 150 | 151 | local levelMap = {...} 152 | 153 | -- ret < 0 : higher priority of a for a and b 154 | -- ret == 0 same priority for a and b 155 | -- ret > 0 lower priority of a for a and b 156 | function comp_func(a, b, scoreA, scoreB, node_ptr_diff) 157 | if scoreA ~= scoreB then 158 | return scoreA - scoreB 159 | end 160 | if levelMap[a] ~= levelMap[b] then 161 | return levelMap[a] - levelMap[b] 162 | end 163 | return node_ptr_diff 164 | end 165 | sl = lskiplist:new(comp_func) 166 | ``` 167 | 168 | ### sl:insert(data, score) 169 | score : default == 0 170 | 171 | ### sl:update(data, score) 172 | if none or nil for score, delete data; 173 | insert if data does exist; 174 | if data exists, delete data first, and then update score, insert at last; 175 | 176 | ### sl[data] = score 177 | it's the same with sl:update(data, score) 178 | 179 | ### sl:delete(data) 180 | 181 | ### sl[data] = nil 182 | it's the same with sl:delete(data) or sl:update(data, nil) 183 | 184 | ### sl:exists(data) 185 | return true if exists, or false if not 186 | 187 | ### sl:get_by_rank(rank) 188 | return data, score if rank exists 189 | 190 | ### sl:del_by_rank(rank) 191 | 192 | ### sl:del_by_rank_range(rankMin, rankMax) 193 | 194 | ### sl:rank_of(data) 195 | return rank of data 196 | 197 | ### sl:rank_range(rankMin, rankMax) 198 | return an table {[rankMin] = data1, [rankMin + 1] = data2, ..., [rankMax] = dataN} 199 | 200 | ### sl:get_score(data) 201 | it's the same with sl[data] 202 | 203 | ### sl:score_range(scoreMin, scoreMax) 204 | return list, rankMin, rankMax 205 | 206 | list = {data1, data2, ..., dataN} 207 | 208 | ### sl:next(data) 209 | return next value for rank of data 210 | 211 | ### sl:prev() 212 | return prev value for rank of data 213 | 214 | ### sl:size() 215 | sizeof sl 216 | 217 | ### #sl 218 | it's the same with sl:size() 219 | 220 | ### sl:rank_pairs(rankMin[, rankMax]) 221 | iterator for sl; 222 | 223 | rankMax : default == sl:size() 224 | 225 | example: 226 | ``` 227 | for rank, data, score in sl:rank_pairs(rankMin, rankMax) do 228 | print(rank, data, score) 229 | end 230 | ``` 231 | 232 | ## TODO 233 | multi thread support 234 | -------------------------------------------------------------------------------- /lua-bind/benchmark.lua: -------------------------------------------------------------------------------- 1 | lskiplist = require "lskiplist" 2 | 3 | function comp(a, b, scoreA, scoreB, pdiff) 4 | if scoreA ~= scoreB then 5 | return scoreA - scoreB 6 | end 7 | if a ~= b then 8 | return a - b 9 | end 10 | return pdiff 11 | end 12 | 13 | local map = {} 14 | 15 | function benchmark(f, ...) 16 | local s = os.clock() 17 | f(...) 18 | return os.clock() - s 19 | end 20 | 21 | local sl = lskiplist.new(comp) 22 | 23 | function insert(len) 24 | for i=1, len do 25 | sl:insert(i, map[i]) 26 | end 27 | end 28 | 29 | function update(len) 30 | for i=1, len do 31 | sl[i] = map[i] 32 | end 33 | end 34 | 35 | function rank_range(count, map_len, range) 36 | for j = 1, count do 37 | local s = math.random(1, map_len - range) 38 | local list = sl:rank_range(s, s + range) 39 | end 40 | end 41 | 42 | function rank_of(test_count, map_len) 43 | for i = 1, test_count do 44 | local s = math.random(1, map_len) 45 | sl:rank_of(s) 46 | end 47 | end 48 | 49 | function get_by_rank(test_count, map_len) 50 | for i = 1, test_count do 51 | local r = math.random(1, map_len) 52 | sl:get_by_rank(r) 53 | end 54 | end 55 | 56 | function delete() 57 | local len = #map 58 | for i=1, len do 59 | sl[i] = nil 60 | end 61 | end 62 | 63 | function printf(fmt, ...) 64 | print(string.format(fmt, ...)) 65 | end 66 | 67 | function main(args) 68 | local map_len = tonumber(args and args[1]) or 1e5 69 | for i = 1, map_len do 70 | map[i] = math.random() 71 | end 72 | printf("insert, create() size=%d, time=%.5f", map_len, benchmark(insert, map_len)) 73 | printf("update, sl:size() == %d, update cnt=%d time=%.5f", map_len, map_len, benchmark(update, map_len)) 74 | printf("rank_range sl:size() == %d,cnt=%d(x, x+50) time=%.5f", map_len, map_len, benchmark(rank_range, map_len, map_len, 50)) 75 | printf("rank_of sl:size() == %d,cnt=%d,time=%.5f", map_len, map_len, benchmark(rank_of, map_len, map_len)) 76 | printf("get_by_rank sl:size() == %d,cnt=%d,time=%.5f", map_len, map_len, benchmark(get_by_rank, map_len, map_len)) 77 | printf("delete sl:size() == %d,cnt=%d,time=%.5f", map_len, map_len, benchmark(delete)) 78 | end 79 | 80 | main(arg) 81 | -------------------------------------------------------------------------------- /lua-bind/example.lua: -------------------------------------------------------------------------------- 1 | lskiplist = require "lskiplist" 2 | 3 | local sl = lskiplist.new(function(a, b, scoreA, scoreB, pdiff) 4 | if scoreA ~= scoreB then 5 | return scoreA - scoreB 6 | end 7 | if a ~= b then 8 | return a - b 9 | end 10 | return pdiff 11 | end) 12 | 13 | for i = 1, 10 do 14 | local score = math.random(1, 1000) 15 | sl:insert(i, score) 16 | end 17 | 18 | local t = sl:rank_range() 19 | for rank, v in pairs(t) do 20 | local score = sl:get_score(v) 21 | print("sorted", rank, v, sl:get_score(v)) 22 | end 23 | 24 | local delV, delScore = sl:del_by_rank(5) 25 | print("del_by_rank data:", delV, delScore) 26 | 27 | local s, e = 2, 8 28 | local list = sl:rank_range(s, e) 29 | for i, v in pairs(list) do 30 | local score = sl:get_score(v) 31 | print("after delete", i + s - 1, v, score) 32 | end 33 | 34 | print(sl:rank_of(7)) 35 | sl:update(7, -1) 36 | for i, v in pairs(sl:rank_range()) do 37 | print("rank", i, v, sl:get_score(v)) 38 | end 39 | for rank, v, score in sl:rank_pairs(1, 5) do 40 | print("rank_pairs", rank, v, score) 41 | end 42 | sl:update(7, 128) 43 | sl:update(99, 128) 44 | sl[234] = 127 45 | print("score of 7", sl[7]) 46 | 47 | sl[234] = 125 48 | sl[3] = nil 49 | 50 | print("size", #sl, sl:size()) 51 | local srange, rankMin = sl:score_range(20, 679) 52 | for i, v in pairs(srange) do 53 | print("score range of", rankMin + i - 1, v, sl:get_score(v)) 54 | end 55 | 56 | -------------------------------------------------------------------------------- /lua-bind/lskiplist.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "skiplist.h" 12 | 13 | #if LUA_VERSION_NUM < 502 14 | # ifndef luaL_newlib 15 | # define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l)) 16 | # endif 17 | # ifndef lua_setuservalue 18 | # define lua_setuservalue(L, n) lua_setfenv(L, n) 19 | # endif 20 | # ifndef lua_getuservalue 21 | # define lua_getuservalue(L, n) lua_getfenv(L, n) 22 | # endif 23 | #endif 24 | 25 | #define EPSILON 1e-15 26 | 27 | #define ENABLE_LSL_INDEX 1 28 | 29 | 30 | #define CLASS_SKIPLIST "cls{skiplist}" 31 | #define CHECK_SL(L, n) ((sl_t *)luaL_checkudata(L, n, CLASS_SKIPLIST)) 32 | 33 | /** 34 | * #define SL_ALWAYS_FETCH 1 35 | */ 36 | 37 | #ifndef SL_ALWAYS_FETCH 38 | 39 | #define SL_COMP_INIT(L, slIdx, top, sl) do { \ 40 | if (sl->comp == compByScore) break; \ 41 | top = lua_gettop(L); \ 42 | lua_getuservalue(L, slIdx); \ 43 | lua_getfield(L, -1, "value_map"); \ 44 | lua_getfield(L, -2, "comp_func"); \ 45 | } while (0); 46 | 47 | #define SL_COMP_FINAL(L, top, sl) do { \ 48 | if (sl->comp == compByScore) break; \ 49 | lua_settop(L, top); \ 50 | } while (0); 51 | 52 | #else 53 | # define SL_COMP_INIT(L, slIdx, top, sl) (void )(top) 54 | # define SL_COMP_FINAL(L, top, sl) (void)(top) 55 | #endif 56 | 57 | #define ENABLE_LSL_DEBUG 58 | #ifdef ENABLE_LSL_DEBUG 59 | # define DLOG(fmt, ...) fprintf(stderr, "" fmt "\n", ##__VA_ARGS__) 60 | #else 61 | # define DLOG(...) 62 | #endif 63 | 64 | static slNode_t *luac__get_node(lua_State *L, int sl_idx, int node_idx) 65 | { 66 | sl_t *sl; 67 | 68 | int top = lua_gettop(L); 69 | 70 | sl = CHECK_SL(L, sl_idx); 71 | 72 | if (sl_idx < 0) 73 | sl_idx = top + sl_idx + 1; 74 | if (node_idx < 0) 75 | node_idx = top + node_idx + 1; 76 | 77 | luaL_argcheck(L, !lua_isnoneornil(L, node_idx), node_idx, 78 | "number|string|table|udata required!"); 79 | 80 | lua_getuservalue(L, sl_idx); 81 | lua_getfield(L, -1, "node_map"); 82 | 83 | lua_pushvalue(L, node_idx); 84 | lua_rawget(L, -2); 85 | if (lua_isuserdata(L, -1)) { 86 | slNode_t *p = lua_touserdata(L, -1); 87 | lua_settop(L, top); 88 | return p; 89 | } 90 | lua_settop(L, top); 91 | return NULL; 92 | } 93 | 94 | static int compByScore(slNode_t *nodeA, slNode_t *nodeB, sl_t *sl, void *ctx) 95 | { 96 | ptrdiff_t diff; 97 | double score_diff; 98 | int asec = sl->udata == NULL ? 1 : -1; 99 | 100 | score_diff = nodeA->score - nodeB->score; 101 | if (fabs(score_diff) > EPSILON) { 102 | if (score_diff * asec < 0) 103 | return -1; 104 | else 105 | return 1; 106 | } 107 | diff = (const char *)nodeA - (const char *)nodeB; 108 | if (diff == 0) 109 | return 0; 110 | return diff > 0 ? 1 : -1; 111 | } 112 | 113 | static int compInLua(slNode_t *nodeA, slNode_t *nodeB, sl_t *sl, void *ctx) 114 | { 115 | lua_State *L = ctx; 116 | int top = lua_gettop(L); 117 | ptrdiff_t diff; 118 | int idiff; 119 | int ret; 120 | int offset = 0; 121 | double retf; 122 | 123 | diff = (const char *)nodeA - (const char *)nodeB; 124 | if (diff == 0) 125 | return 0; 126 | else 127 | idiff = diff > 0 ? 1 : -1; 128 | lua_checkstack(L, 9); 129 | #ifdef SL_ALWAYS_FETCH 130 | lua_getuservalue(L, 1); 131 | lua_getfield(L, -1, "value_map"); 132 | lua_getfield(L, -2, "comp_func"); /*value_map, comp_func*/ 133 | #else 134 | offset = 1; 135 | lua_pushvalue(L, -1); 136 | if (!lua_isfunction(L, -1)) { 137 | const char *typename = luaL_typename(L, -1); 138 | return luaL_error(L, "function not found! type=%s, value=%s,top=%d", typename, lua_tostring(L, -1), top); 139 | } 140 | #endif 141 | lua_pushlightuserdata(L, nodeA); 142 | lua_rawget(L, -3 - offset); /*value_map, comp_func, valueA*/ 143 | 144 | lua_pushlightuserdata(L, nodeB); 145 | lua_rawget(L, -4 - offset); /*value_map, comp_func, valueA, valueB*/ 146 | 147 | lua_pushnumber(L, nodeA->score); 148 | lua_pushnumber(L, nodeB->score); /*value_map, comp_func, valueA, valueB, scoreA, scoreB*/ 149 | 150 | lua_pushnumber(L, idiff); /*value_map, comp_func, valueA, valueB, scoreA, scoreB, idiff*/ 151 | 152 | ret = lua_pcall(L, 5, 1, 0); 153 | if (ret != 0) 154 | return luaL_error(L, "comp error %s", lua_tostring(L, -1)); 155 | 156 | if (!lua_isnumber(L, -1)) { 157 | return luaL_error(L, "integer required for comp func"); 158 | } 159 | retf = lua_tonumber(L, -1); 160 | if (fabs(retf) < EPSILON) 161 | ret = 0; 162 | else if (retf > 0) 163 | ret = 1; 164 | else 165 | ret = -1; 166 | 167 | lua_settop(L, top); 168 | return ret; 169 | } 170 | 171 | static int lua__new(lua_State *L) 172 | { 173 | sl_t *sl; 174 | 175 | if (lua_isnone(L, 1)) 176 | lua_pushnil(L); 177 | if (!lua_isfunction(L, 1) && !lua_isnil(L, 1) && !lua_isboolean(L, 1)) { 178 | luaL_argcheck(L, 0, 1, "compare function|boolean"); 179 | return 0; 180 | } 181 | 182 | sl = (sl_t *)lua_newuserdata(L, sizeof(sl_t)); 183 | slInit(sl); 184 | 185 | if (lua_isfunction(L, 1)) { 186 | sl->comp = compInLua; 187 | } else { 188 | sl->comp = compByScore; 189 | sl->udata = lua_toboolean(L, 1) ? sl : NULL; 190 | } 191 | 192 | luaL_getmetatable(L, CLASS_SKIPLIST); 193 | lua_setmetatable(L, -2); 194 | 195 | lua_createtable(L, 0, 3); 196 | lua_pushvalue(L, 1); 197 | lua_setfield(L, -2, "comp_func"); 198 | 199 | lua_newtable(L); 200 | lua_setfield(L, -2, "value_map"); /* k = node_ptr, value = lua_value*/ 201 | 202 | lua_newtable(L); 203 | lua_setfield(L, -2, "node_map"); /* k = lua_value, value = node_ptr*/ 204 | 205 | lua_setuservalue(L, -2); 206 | 207 | return 1; 208 | } 209 | 210 | static int lua__skiplist_gc(lua_State *L) 211 | { 212 | sl_t *sl = CHECK_SL(L, 1); 213 | slDestroy(sl, NULL, NULL); 214 | return 0; 215 | } 216 | 217 | static int lua__insert(lua_State *L) 218 | { 219 | double score; 220 | sl_t *sl; 221 | slNode_t *node; 222 | int level; 223 | int cur = 0; 224 | 225 | sl = CHECK_SL(L, 1); 226 | node = luac__get_node(L, 1, 2); 227 | score = luaL_optnumber(L, 3, 0.0); 228 | if (node != NULL) 229 | return luaL_error(L, "value exists"); 230 | 231 | level = slRandomLevel(); 232 | if ((node = slCreateNode(level, NULL, score)) == NULL) 233 | return luaL_error(L, "no memory in lua__insert"); 234 | 235 | node->udata = node; 236 | lua_getuservalue(L, 1); 237 | lua_getfield(L, -1, "node_map"); 238 | lua_pushvalue(L, 2); 239 | lua_pushlightuserdata(L, (void *)node); 240 | lua_rawset(L, -3); 241 | lua_pop(L, 1); 242 | 243 | lua_getfield(L, -1, "value_map"); 244 | lua_pushlightuserdata(L, (void *)node); 245 | lua_pushvalue(L, 2); 246 | lua_rawset(L, -3); 247 | lua_pop(L, 1); 248 | 249 | SL_COMP_INIT(L, 1, cur, sl); 250 | slInsertNode(sl, node, L); 251 | SL_COMP_FINAL(L, cur, sl); 252 | lua_pushlightuserdata(L, node); 253 | return 1; 254 | } 255 | 256 | static int lua__update(lua_State *L) 257 | { 258 | int level; 259 | double score; 260 | int cur = 0; 261 | sl_t *sl = CHECK_SL(L, 1); 262 | slNode_t *node = luac__get_node(L, 1, 2); 263 | if (lua_isnoneornil(L, 3) && node != NULL) { 264 | int ret; 265 | SL_COMP_INIT(L, 1, cur, sl); 266 | ret = slDeleteNode(sl, node, L, NULL); 267 | SL_COMP_FINAL(L, cur, sl); 268 | if (ret != 0) { 269 | return luaL_error(L, "compare function implementation maybe error in %s:%d", __FUNCTION__, __LINE__); 270 | } 271 | 272 | lua_getuservalue(L, 1); 273 | 274 | lua_getfield(L, -1, "node_map"); 275 | lua_pushvalue(L, 2); 276 | lua_pushnil(L); 277 | lua_rawset(L, -3); 278 | lua_pop(L, 1); 279 | 280 | lua_getfield(L, -1, "value_map"); 281 | lua_pushlightuserdata(L, (void *)node); 282 | lua_pushnil(L); 283 | lua_rawset(L, -3); 284 | lua_pop(L, 1); 285 | lua_settop(L, 3); 286 | return 0; 287 | } 288 | score = luaL_checknumber(L, 3); 289 | if (node != NULL) { 290 | slNode_t *pNode = NULL; 291 | int ret; 292 | SL_COMP_INIT(L, 1, cur, sl); 293 | ret = slDeleteNode(sl, node, L, &pNode); 294 | SL_COMP_FINAL(L, cur, sl); 295 | if (ret != 0) { 296 | return luaL_error(L, "compare function implementation maybe error in %s:%d", __FUNCTION__, __LINE__); 297 | } 298 | node->score = score; 299 | } else { 300 | level = slRandomLevel(); 301 | if ((node = slCreateNode(level, NULL, score)) == NULL) { 302 | return luaL_error(L, "no memory in lua__update"); 303 | } 304 | node->udata = node; 305 | lua_getuservalue(L, 1); 306 | lua_getfield(L, -1, "node_map"); 307 | lua_pushvalue(L, 2); 308 | lua_pushlightuserdata(L, (void *)node); 309 | lua_rawset(L, -3); 310 | lua_pop(L, 1); 311 | 312 | lua_getfield(L, -1, "value_map"); 313 | lua_pushlightuserdata(L, (void *)node); 314 | lua_pushvalue(L, 2); 315 | lua_rawset(L, -3); 316 | lua_pop(L, 1); 317 | } 318 | SL_COMP_INIT(L, 1, cur, sl); 319 | slInsertNode(sl, node, L); 320 | SL_COMP_FINAL(L, cur, sl); 321 | lua_pushlightuserdata(L, node); 322 | return 1; 323 | } 324 | 325 | #if ENABLE_LSL_INDEX 326 | static int lua__index(lua_State *L) 327 | { 328 | slNode_t *node; 329 | sl_t *sl = CHECK_SL(L, 1); 330 | (void)sl; 331 | if (lua_type(L, 2) == LUA_TSTRING) { 332 | lua_pushvalue(L, lua_upvalueindex(1)); 333 | lua_pushvalue(L, 2); 334 | lua_rawget(L, -2); 335 | if (!lua_isnil(L, -1)) 336 | return 1; 337 | } 338 | node = luac__get_node(L, 1, 2); 339 | if (node == NULL) { 340 | lua_pushnil(L); 341 | return 0; 342 | } 343 | lua_pushnumber(L, node->score); 344 | return 1; 345 | } 346 | #endif 347 | 348 | static int lua__delete(lua_State *L) 349 | { 350 | int ret; 351 | int cur = 0; 352 | sl_t *sl = CHECK_SL(L, 1); 353 | slNode_t *node = luac__get_node(L, 1, 2); 354 | if (node == NULL) 355 | return 0; 356 | 357 | SL_COMP_INIT(L, 1, cur, sl); 358 | ret = slDeleteNode(sl, node, L, NULL); 359 | SL_COMP_FINAL(L, cur, sl); 360 | if (ret != 0) { 361 | return luaL_error(L, "compare function implementation maybe error in %s:%d", __FUNCTION__, __LINE__); 362 | } 363 | 364 | lua_getuservalue(L, 1); 365 | 366 | lua_getfield(L, -1, "node_map"); 367 | lua_pushvalue(L, 2); 368 | lua_pushnil(L); 369 | lua_rawset(L, -3); 370 | lua_pop(L, 1); 371 | 372 | lua_getfield(L, -1, "value_map"); 373 | lua_pushlightuserdata(L, (void *)node); 374 | lua_pushnil(L); 375 | lua_rawset(L, -3); 376 | lua_pop(L, 1); 377 | 378 | lua_pushboolean(L, 1); 379 | return 1; 380 | } 381 | 382 | static int lua__exists(lua_State *L) 383 | { 384 | sl_t *sl = CHECK_SL(L, 1); 385 | slNode_t *node = luac__get_node(L, 1, 2); 386 | (void)sl; 387 | lua_pushboolean(L, node != NULL); 388 | return 1; 389 | } 390 | 391 | static int lua__size(lua_State *L) 392 | { 393 | sl_t *sl = CHECK_SL(L, 1); 394 | lua_pushinteger(L, sl->size); 395 | return 1; 396 | } 397 | 398 | static int lua__rank_iterator(lua_State *L) 399 | { 400 | slNode_t *node; 401 | slNode_t *next; 402 | sl_t *sl = CHECK_SL(L, lua_upvalueindex(1)); 403 | int last = (int)lua_tointeger(L, lua_upvalueindex(2)); 404 | int rankMax = (int)lua_tointeger(L, lua_upvalueindex(3)); 405 | node = (slNode_t *)lua_touserdata(L, lua_upvalueindex(4)); 406 | (void) sl; 407 | if (last > rankMax) 408 | return 0; 409 | 410 | if (node == NULL) 411 | return 0; 412 | 413 | lua_pushinteger(L, last + 1); 414 | lua_replace(L, lua_upvalueindex(2)); 415 | 416 | next = SL_NEXT(node); 417 | lua_pushlightuserdata(L, (void *)next); 418 | lua_replace(L, lua_upvalueindex(4)); 419 | 420 | lua_getuservalue(L, lua_upvalueindex(1)); 421 | lua_getfield(L, -1, "value_map"); 422 | lua_pushlightuserdata(L, (void *)node); 423 | lua_rawget(L, -2); 424 | lua_pushinteger(L, last); 425 | lua_insert(L, -2); 426 | lua_pushnumber(L, node->score); 427 | return 3; 428 | } 429 | 430 | static int lua__rank_pairs(lua_State *L) 431 | { 432 | slNode_t *node; 433 | sl_t *sl = CHECK_SL(L, 1); 434 | int rankMin = luaL_optinteger(L, 2, 1); 435 | int rankMax = luaL_optinteger(L, 3, sl->size); 436 | 437 | if (rankMin < 1 || rankMin > rankMax || rankMax > sl->size) 438 | return luaL_error(L, 439 | "range error! range should be[1, %d],but[%d, %d]", 440 | sl->size, rankMin, rankMax); 441 | 442 | node = slGetNodeByRank(sl, rankMin); 443 | lua_pushvalue(L, 1); 444 | lua_pushinteger(L, rankMin); 445 | lua_pushinteger(L, rankMax); 446 | lua_pushlightuserdata(L, (void *)node); 447 | lua_pushcclosure(L, lua__rank_iterator, 4); 448 | return 1; 449 | } 450 | 451 | static int lua__get_by_rank(lua_State *L) 452 | { 453 | slNode_t *node; 454 | sl_t *sl = CHECK_SL(L, 1); 455 | int rank = luaL_checkinteger(L, 2); 456 | if (rank <= 0 || rank > sl->size) { 457 | lua_pushnil(L); 458 | lua_pushliteral(L, "err index"); 459 | return 2; 460 | } 461 | if (rank == 1) { 462 | node = SL_FIRST(sl); 463 | } else if (rank == sl->size) { 464 | node = SL_LAST(sl); 465 | } else { 466 | node = slGetNodeByRank(sl, rank); 467 | } 468 | if (node == NULL) 469 | return 0; 470 | lua_getuservalue(L, 1); 471 | lua_getfield(L, -1, "value_map"); 472 | lua_pushlightuserdata(L, (void *)node); 473 | lua_rawget(L, -2); 474 | lua_pushnumber(L, node->score); 475 | return 2; 476 | } 477 | 478 | static int lua__del_by_rank(lua_State *L) 479 | { 480 | int cur = 0; 481 | int ret; 482 | slNode_t *node; 483 | double score; 484 | sl_t *sl = CHECK_SL(L, 1); 485 | int rank = luaL_checkinteger(L, 2); 486 | if (rank <= 0 || rank > sl->size) { 487 | lua_pushnil(L); 488 | lua_pushliteral(L, "err index"); 489 | return 2; 490 | } 491 | if (rank == 1) { 492 | node = SL_FIRST(sl); 493 | } else if (rank == sl->size) { 494 | node = SL_LAST(sl); 495 | } else { 496 | node = slGetNodeByRank(sl, rank); 497 | } 498 | if (node == NULL) 499 | return 0; 500 | score = node->score; 501 | lua_getuservalue(L, 1); 502 | lua_getfield(L, -1, "value_map"); 503 | lua_pushlightuserdata(L, (void *)node); 504 | lua_rawget(L, -2); 505 | 506 | SL_COMP_INIT(L, 1, cur, sl); 507 | ret = slDeleteNode(sl, node, L, NULL); 508 | SL_COMP_FINAL(L, cur, sl); 509 | if (ret != 0) { 510 | return luaL_error(L, "compare function implementation maybe error in %s:%d", __FUNCTION__, __LINE__); 511 | } 512 | 513 | /*uservalue, value_map, value*/ 514 | lua_getfield(L, -3, "node_map"); 515 | /*uservalue, value_map, value, node_map*/ 516 | lua_pushvalue(L, -2); 517 | lua_pushnil(L); 518 | lua_rawset(L, -3); 519 | lua_pop(L, 2); 520 | 521 | /*uservalue, value_map*/ 522 | lua_pushlightuserdata(L, (void *)node); 523 | lua_rawget(L, -2); 524 | /*uservalue, value_map, value*/ 525 | 526 | lua_pushlightuserdata(L, (void *)node); 527 | lua_pushnil(L); 528 | lua_rawset(L, -4); 529 | 530 | /*uservalue, value_map, value*/ 531 | 532 | lua_pushnumber(L, score); 533 | 534 | /*uservalue, value_map, value, score*/ 535 | return 2; 536 | } 537 | 538 | static int lua__get_score(lua_State *L) 539 | { 540 | sl_t *sl = CHECK_SL(L, 1); 541 | slNode_t *node = luac__get_node(L, 1, 2); 542 | (void)sl; 543 | if (node == NULL) 544 | return 0; 545 | lua_pushnumber(L, node->score); 546 | return 1; 547 | } 548 | 549 | static int lua__score_range(lua_State *L) 550 | { 551 | int i; 552 | slNode_t *pMin, *pMax, *node; 553 | int cur = 0; 554 | int rank; 555 | sl_t *sl = CHECK_SL(L, 1); 556 | double min = luaL_checknumber(L, 2); 557 | double max = luaL_optnumber(L, 3, DBL_MAX); 558 | 559 | luaL_argcheck(L, min < max, 3, "max should greater or equal than min"); 560 | pMin = slFirstGEThan(sl, min); 561 | pMax = slLastLEThan(sl, max); 562 | if (pMin == NULL && pMax == NULL) 563 | return 0; 564 | lua_getuservalue(L, 1); 565 | lua_getfield(L, -1, "value_map"); 566 | lua_newtable(L); 567 | for (node = pMin, i = 1; node != SL_NEXT(pMax); node = SL_NEXT(node)) { 568 | lua_pushlightuserdata(L, (void *)node); 569 | lua_rawget(L, -3); 570 | lua_rawseti(L, -2, i++); 571 | } 572 | SL_COMP_INIT(L, 1, cur, sl); 573 | rank = slGetRank(sl, pMin, L); 574 | SL_COMP_FINAL(L, cur, sl); 575 | lua_pushinteger(L, rank); 576 | lua_pushinteger(L, rank + i - 2); 577 | return 3; 578 | } 579 | 580 | static int lua__rank_of(lua_State *L) 581 | { 582 | int rank = 0; 583 | sl_t *sl = CHECK_SL(L, 1); 584 | int cur = 0; 585 | slNode_t *node = luac__get_node(L, 1, 2); 586 | if (node != NULL) { 587 | SL_COMP_INIT(L, 1, cur, sl); 588 | rank = slGetRank(sl, node, L); 589 | SL_COMP_FINAL(L, cur, sl); 590 | } 591 | lua_pushinteger(L, rank); 592 | return 1; 593 | } 594 | 595 | static int lua__rank_range(lua_State *L) 596 | { 597 | int n; 598 | sl_t *sl = CHECK_SL(L, 1); 599 | slNode_t *node; 600 | int rankMin = luaL_optinteger(L, 2, 1); 601 | int rankMax = luaL_optinteger(L, 3, sl->size); 602 | 603 | if (sl->size == 0) { 604 | lua_createtable(L, 0, 0); 605 | return 1; 606 | } 607 | 608 | if (rankMin <= 0 || rankMin > rankMax || rankMax > sl->size) 609 | return luaL_error(L, "range error!"); 610 | 611 | lua_getuservalue(L, 1); 612 | lua_getfield(L, -1, "value_map"); 613 | 614 | lua_createtable(L, rankMax - rankMin + 1, 0); 615 | SL_FOREACH_RANGE(sl, rankMin, rankMax, node, n) { 616 | lua_pushlightuserdata(L, (void *)node); 617 | lua_rawget(L, -3); 618 | lua_rawseti(L, -2, n + 1); 619 | } 620 | return 1; 621 | } 622 | 623 | static int lua__next(lua_State *L) 624 | { 625 | slNode_t *next = NULL; 626 | sl_t *sl = CHECK_SL(L, 1); 627 | slNode_t *node = luac__get_node(L, 1, 2); 628 | (void)sl; 629 | if (node == NULL) 630 | return 0; 631 | next = SL_NEXT(node); 632 | lua_getuservalue(L, 1); 633 | lua_getfield(L, -1, "value_map"); 634 | lua_pushlightuserdata(L, (void *)next); 635 | lua_rawget(L, -2); 636 | return 1; 637 | } 638 | 639 | static int lua__prev(lua_State *L) 640 | { 641 | slNode_t *prev = NULL; 642 | sl_t *sl = CHECK_SL(L, 1); 643 | slNode_t *node = luac__get_node(L, 1, 2); 644 | (void)sl; 645 | if (node == NULL) 646 | return 0; 647 | prev = SL_PREV(node); 648 | lua_getuservalue(L, 1); 649 | lua_getfield(L, -1, "value_map"); 650 | lua_pushlightuserdata(L, (void *)prev); 651 | lua_rawget(L, -2); 652 | return 1; 653 | } 654 | 655 | static void deleteCb(void *udata, void *ctx) 656 | { 657 | lua_State *L = ctx; 658 | int top = lua_gettop(L); 659 | /* node->udata = node, see lua__insert */ 660 | 661 | /*sl, min, max, uservalue, value_map, node_map, udata(node)*/ 662 | lua_pushlightuserdata(L, udata); 663 | 664 | /*sl, min, max, uservalue, value_map, node_map, value*/ 665 | lua_rawget(L, 5); 666 | 667 | /*sl, min, max, uservalue, value_map, node_map, value, nil*/ 668 | lua_pushnil(L); 669 | lua_rawset(L, 6); 670 | /*sl, min, max, uservalue, value_map, node_map*/ 671 | 672 | /*sl, min, max, uservalue, value_map, node_map, nil*/ 673 | /* node->udata = node, see lua__insert */ 674 | lua_pushlightuserdata(L, udata); 675 | lua_pushnil(L); 676 | lua_rawset(L, 5); 677 | lua_settop(L, top); 678 | } 679 | 680 | static int lua__del_rank_range(lua_State *L) 681 | { 682 | sl_t *sl = CHECK_SL(L, 1); 683 | int min = luaL_checkinteger(L, 2); 684 | int max = luaL_optinteger(L, 3, min); 685 | int n; 686 | luaL_argcheck(L, 1 <= min && min <= max && min <= sl->size, 2, "min [1, size]"); 687 | luaL_argcheck(L, 1 <= max && min <= max && max <= sl->size, 3, "max [1, size]"); 688 | lua_settop(L, 3); 689 | lua_getuservalue(L, 1); 690 | lua_getfield(L, -1, "value_map"); /*idx = 5*/ 691 | lua_getfield(L, -2, "node_map"); /*idx = 6*/ 692 | n = slDeleteByRankRange(sl, min, max, deleteCb, L); 693 | lua_pushinteger(L, n); 694 | return 1; 695 | } 696 | 697 | static int opencls__skiplist(lua_State *L) 698 | { 699 | luaL_Reg lmethods[] = { 700 | {"insert", lua__insert}, 701 | {"update", lua__update}, 702 | {"delete", lua__delete}, 703 | {"exists", lua__exists}, 704 | {"get_by_rank", lua__get_by_rank}, 705 | {"del_by_rank", lua__del_by_rank}, 706 | {"del_by_rank_range", lua__del_rank_range}, 707 | {"rank_of", lua__rank_of}, 708 | {"rank_range", lua__rank_range}, 709 | {"get_score", lua__get_score}, 710 | {"score_range", lua__score_range}, 711 | {"next", lua__next}, 712 | {"prev", lua__prev}, 713 | {"size", lua__size}, 714 | {"rank_pairs", lua__rank_pairs}, 715 | {NULL, NULL}, 716 | }; 717 | luaL_newmetatable(L, CLASS_SKIPLIST); 718 | luaL_newlib(L, lmethods); 719 | #if ENABLE_LSL_INDEX 720 | lua_pushcclosure(L, lua__index, 1); 721 | #endif 722 | lua_setfield(L, -2, "__index"); 723 | lua_pushcfunction(L, lua__update); 724 | lua_setfield(L, -2, "__newindex"); 725 | lua_pushcfunction(L, lua__skiplist_gc); 726 | lua_setfield (L, -2, "__gc"); 727 | lua_pushcfunction(L, lua__size); 728 | lua_setfield (L, -2, "__len"); 729 | return 1; 730 | } 731 | 732 | int luaopen_lskiplist(lua_State* L) 733 | { 734 | luaL_Reg lfuncs[] = { 735 | {"new", lua__new}, 736 | {NULL, NULL}, 737 | }; 738 | opencls__skiplist(L); 739 | luaL_newlib(L, lfuncs); 740 | lua_pushnumber(L, EPSILON); 741 | lua_setfield(L, -2, "EPSILON"); 742 | return 1; 743 | } 744 | -------------------------------------------------------------------------------- /lua-bind/test.lua: -------------------------------------------------------------------------------- 1 | local lskiplist = require "lskiplist" 2 | 3 | function dump(sl, prefix) 4 | for rank, v, score in sl:rank_pairs() do 5 | print(prefix, rank, v, score) 6 | end 7 | end 8 | 9 | 10 | local test = {} 11 | function test.insert() 12 | local sl = lskiplist.new() 13 | local list = {2, 5, 1, 3, 9, 7, 6, 8, 4} 14 | for _, i in pairs(list) do 15 | sl:insert(i, i * 10) 16 | end 17 | return sl 18 | end 19 | 20 | function new() 21 | return test.insert() 22 | end 23 | 24 | function test.update(isfunc) 25 | local sl = new() 26 | local list = { 27 | {1, -1, "update"}, 28 | {2, nil, "delete"}, 29 | {0, -2, "insert"}, 30 | } 31 | for _, vv in pairs(list) do 32 | local v, score, action = vv[1], vv[2], vv[3] 33 | if isfunc then 34 | print("update on function, action:", action, v, score, sl:update(v, score)) 35 | else 36 | sl[v] = score 37 | print("update on __newindex, action:", action, v, score) 38 | end 39 | end 40 | dump(sl, "update" .. (isfunc and " on function" or "on __newindex")) 41 | end 42 | 43 | function test.delete() 44 | local sl = new() 45 | local list = {0, 5, 9, 1, 20} 46 | print("try to delete :", table.concat(list, ", ")) 47 | for i, v in pairs(list) do 48 | local ret = sl:delete(v) 49 | print("delete", v, ret) 50 | end 51 | dump(sl, "delete") 52 | return sl 53 | end 54 | 55 | function test.exists() 56 | local sl = new() 57 | local list = {0, 5, 9, 1, 20} 58 | for _, v in pairs(list) do 59 | print("exists", v, sl:exists(v)) 60 | end 61 | end 62 | 63 | function test.get_by_rank() 64 | local sl = new() 65 | local list = { 66 | 1, 2, 5, 9, 0, 20, 67 | } 68 | for _, i in pairs(list) do 69 | print("get_by_rank", i, sl:get_by_rank(i)) 70 | end 71 | end 72 | 73 | function test.del_by_rank() 74 | local sl = new() 75 | local list = { 76 | 9, 1, 2, 5, 0, 20, 77 | } 78 | for _, i in pairs(list) do 79 | local v, score = sl:del_by_rank(i) 80 | print("del_by_rank", i, v, score) 81 | end 82 | end 83 | 84 | function test.del_by_rank_range() 85 | local list = { 86 | {2, 5}, 87 | {5}, 88 | {0}, 89 | {12}, 90 | {0, 3}, 91 | {8, 12}, 92 | {-1, 25}, 93 | {5, 2}, 94 | } 95 | for i, v in pairs(list) do 96 | local sl = new() 97 | local s, e = v[1], v[2] 98 | print("del_by_rank_range", pcall(sl.del_by_rank_range, sl, s, e)) 99 | end 100 | end 101 | 102 | function test.rank_of() 103 | local sl = new() 104 | local list = { 105 | 0, 20, 1, 2, 5, 9 106 | } 107 | for i, v in pairs(list) do 108 | local rank = sl:rank_of(v) 109 | print("rank_of", v, rank) 110 | end 111 | dump(sl, "rank_of !!!!") 112 | end 113 | 114 | function test.rank_range() 115 | local sl = new() 116 | local list = { 117 | {1, 5}, 118 | {2, 3}, 119 | {5}, 120 | {9}, 121 | {}, 122 | {0, 2}, 123 | {8, 20}, 124 | {0, 20}, 125 | {25, 20}, 126 | } 127 | for _, v in pairs(list) do 128 | local s, e = v[1], v[2] 129 | local ok, l, err = pcall(sl.rank_range, sl, s, e) 130 | if ok then 131 | print("rank_range", s, e, "{" .. table.concat(l, ",").."}") 132 | else 133 | print("rank_range, error", s, e, l, err) 134 | end 135 | end 136 | end 137 | 138 | function test.get_score(isfunc) 139 | local sl = new() 140 | local list = { 141 | 0, 20, 1, 2, 5, 9 142 | } 143 | for _, v in pairs(list) do 144 | if isfunc then 145 | local score = sl:get_score(v) 146 | print("get_score", isfunc and "on function" or "on index", v, score) 147 | else 148 | local score = sl[v] 149 | print("get_score", isfunc and "on function" or "on index", v, score) 150 | end 151 | end 152 | end 153 | 154 | function test.score_range() 155 | local sl = new() 156 | local list = { 157 | {10, 50}, 158 | {20, 30}, 159 | {50}, 160 | {90}, 161 | {}, 162 | {0, 20}, 163 | {80, 200}, 164 | {0, 200}, 165 | {250, 200}, 166 | } 167 | for _, v in pairs(list) do 168 | local s, e = v[1], v[2] 169 | local ok, l, rankMin, rankMax = pcall(sl.score_range, sl, s, e) 170 | if ok then 171 | print("rank_range", s, e, rankMin, rankMax, "{" .. table.concat(l, ",").."}") 172 | else 173 | print("rank_range, error", s, e, l) 174 | end 175 | end 176 | end 177 | 178 | function test.next() 179 | local sl = new() 180 | local list = { 181 | 0, 20, 1, 2, 5, 9 182 | } 183 | for i, v in pairs(list) do 184 | print("next", v, sl:next(v)) 185 | end 186 | end 187 | 188 | function test.prev() 189 | local sl = new() 190 | local list = { 191 | 0, 20, 1, 2, 5, 9 192 | } 193 | for i, v in pairs(list) do 194 | print("prev", v, sl:prev(v)) 195 | end 196 | end 197 | 198 | function test.size() 199 | local sl = new() 200 | print("size", sl:size(), #sl) 201 | end 202 | 203 | function test.rank_pairs() 204 | local sl = new() 205 | local list = { 206 | {1, 5}, 207 | {2, 3}, 208 | {5}, 209 | {9}, 210 | {}, 211 | } 212 | for _, v in pairs(list) do 213 | local s, e = v[1], v[2] 214 | print("-----------------------------------------------------") 215 | for rank, v, score in sl:rank_pairs(s, e) do 216 | print("rank_pairs", s, e, rank, v, score) 217 | end 218 | end 219 | end 220 | 221 | function main() 222 | local sl = test.insert() 223 | dump(sl, "insert") 224 | 225 | print("===============") 226 | test.delete() 227 | 228 | print("===============") 229 | test.exists() 230 | 231 | print("===============") 232 | test.update(true) 233 | 234 | print("===============") 235 | test.update(false) 236 | 237 | print("===============") 238 | test.get_by_rank() 239 | 240 | print("===============") 241 | test.del_by_rank() 242 | 243 | print("===============") 244 | test.del_by_rank_range() 245 | 246 | print("===============") 247 | test.rank_of() 248 | 249 | print("===============") 250 | test.rank_range() 251 | 252 | print("===============") 253 | test.get_score(true) 254 | 255 | print("===============") 256 | test.get_score(false) 257 | 258 | print("===============") 259 | test.score_range() 260 | 261 | print("===============") 262 | test.next() 263 | 264 | print("===============") 265 | test.prev() 266 | 267 | print("===============") 268 | test.size() 269 | 270 | print("===============") 271 | test.rank_pairs() 272 | end 273 | 274 | main() 275 | 276 | 277 | -------------------------------------------------------------------------------- /src/skiplist.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "skiplist.h" 7 | 8 | #define ENABLE_SL_DEBUG 0 9 | #if (ENABLE_SL_DEBUG > 0) 10 | # define DLOG(fmt, ...) fprintf(stderr, "" fmt "\n", ##__VA_ARGS__) 11 | #else 12 | # define DLOG(...) 13 | #endif 14 | 15 | 16 | static void slInitNode(slNode_t *node, int level, void *udata, double score); 17 | static int internalComp(slNode_t *nodeA, slNode_t *nodeB, sl_t *sl, void *ctx); 18 | static void slDeleteNodeUpdate(sl_t *sl, slNode_t *node, slNode_t **update); 19 | 20 | int slRandomLevel() 21 | { 22 | int level = 1; 23 | while((rand() & 0xffff) < (SKIPLIST_P * 0xffff)) 24 | level += 1; 25 | return (level < SKIPLIST_MAXLEVEL) ? level : SKIPLIST_MAXLEVEL; 26 | } 27 | 28 | static int internalComp(slNode_t *nodeA, slNode_t *nodeB, sl_t *sl, void *ctx) 29 | { 30 | ptrdiff_t d; 31 | if (nodeA->score != nodeB->score) 32 | return nodeA->score - nodeB->score < 0 ? -1 : 1; 33 | 34 | d = (const char *)(nodeA->udata == NULL ? nodeA : nodeA->udata) 35 | - (const char *)(nodeB->udata == NULL ? nodeB : nodeB->udata); 36 | 37 | if (d == 0) 38 | return 0; 39 | return d < 0 ? -1 : 1; 40 | } 41 | 42 | void slInit(sl_t *sl) 43 | { 44 | sl->level = 1; 45 | sl->size = 0; 46 | sl->tail = NULL; 47 | sl->comp = internalComp; 48 | slInitNode(SL_HEAD(sl), SKIPLIST_MAXLEVEL, NULL, DBL_MIN); 49 | } 50 | 51 | sl_t * slCreate() 52 | { 53 | sl_t *sl = malloc(sizeof(*sl)); 54 | if (sl == NULL) { 55 | return NULL; 56 | } 57 | slInit(sl); 58 | sl->udata = NULL; 59 | return sl; 60 | } 61 | 62 | slCompareCb slSetCompareCb(sl_t *sl, slCompareCb comp) 63 | { 64 | slCompareCb old = sl->comp; 65 | sl->comp = comp; 66 | return old; 67 | } 68 | 69 | void slDestroy(sl_t *sl, slFreeCb freeCb, void *ctx) 70 | { 71 | slNode_t *node; 72 | slNode_t *next; 73 | for (node = SL_FIRST(sl); node != NULL; node = next) { 74 | next = node->level[0].next; 75 | slFreeNode(node, freeCb, ctx); 76 | } 77 | } 78 | 79 | void slFree(sl_t *sl, slFreeCb freeCb, void *ctx) 80 | { 81 | slDestroy(sl, freeCb, ctx); 82 | free(sl); 83 | } 84 | 85 | static void slInitNode(slNode_t *node, int level, void *udata, double score) 86 | { 87 | int i; 88 | node->score = score; 89 | node->udata = udata; 90 | node->prev = NULL; 91 | node->levelSize = level; 92 | for (i = 0; i < level; i++) { 93 | node->level[i].next = NULL; 94 | node->level[i].span = 0; 95 | } 96 | } 97 | 98 | slNode_t * slCreateNode(int level, void *udata, double score) 99 | { 100 | size_t node_sz = sizeof(slNode_t) + sizeof(struct levelNode_s) * (level - 1); 101 | slNode_t *node = malloc(node_sz); 102 | if (node == NULL) 103 | goto finished; 104 | slInitNode(node, level, udata, score); 105 | finished: 106 | return node; 107 | } 108 | 109 | void slFreeNode(slNode_t *node, slFreeCb freeCb, void *ctx) 110 | { 111 | if (freeCb != NULL) { 112 | freeCb(node->udata, ctx); 113 | } 114 | free(node); 115 | } 116 | 117 | void slInsertNode(sl_t *sl, slNode_t *node, void *ctx) 118 | { 119 | int level; 120 | slNode_t *update[SKIPLIST_MAXLEVEL]; 121 | slNode_t *p; 122 | int rank[SKIPLIST_MAXLEVEL]; 123 | int i; 124 | p = SL_HEAD(sl); 125 | for (i = sl->level - 1; i >= 0; i--) { 126 | rank[i] = i == (sl->level-1) ? 0 : rank[i+1]; 127 | while (p->level[i].next != NULL 128 | && (sl->comp(p->level[i].next, node, sl, ctx) < 0)) { 129 | rank[i] += p->level[i].span; 130 | p = p->level[i].next; 131 | } 132 | update[i] = p; 133 | } 134 | level = node->levelSize; 135 | if (level > sl->level) { 136 | for (i = sl->level; i < level; i++) { 137 | rank[i] = 0; 138 | update[i] = SL_HEAD(sl); 139 | update[i]->level[i].span = sl->size; 140 | } 141 | sl->level = level; 142 | } 143 | for (i = 0; i < level; i++) { 144 | node->level[i].next = update[i]->level[i].next; 145 | update[i]->level[i].next = node; 146 | 147 | node->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]); 148 | update[i]->level[i].span = rank[0] - rank[i] + 1; 149 | } 150 | for (i = level; i < sl->level; i++) { 151 | update[i]->level[i].span++; 152 | } 153 | node->prev = (update[0] == SL_HEAD(sl)) ? NULL : update[0]; 154 | if (node->level[0].next) 155 | node->level[0].next->prev = node; 156 | else 157 | sl->tail = node; 158 | sl->size++; 159 | } 160 | 161 | static void slDeleteNodeUpdate(sl_t *sl, slNode_t *node, slNode_t **update) 162 | { 163 | int i; 164 | slNode_t *header; 165 | for (i = 0; i < sl->level; i++) { 166 | if (update[i]->level[i].next == node) { 167 | update[i]->level[i].span += node->level[i].span - 1; 168 | update[i]->level[i].next = node->level[i].next; 169 | } else { 170 | update[i]->level[i].span -= 1; 171 | } 172 | } 173 | if (node->level[0].next != NULL) { 174 | node->level[0].next->prev = node->prev; 175 | } else { 176 | sl->tail = node->prev; 177 | } 178 | header = SL_HEAD(sl); 179 | while(sl->level > 1 && header->level[sl->level-1].next == NULL) 180 | sl->level--; 181 | sl->size--; 182 | } 183 | 184 | /** 185 | * call slFreeNode by yourself after slDeleteNode if pNode == NULL 186 | */ 187 | int slDeleteNode(sl_t *sl, slNode_t *node, void *ctx, slNode_t **pNode) 188 | { 189 | int i; 190 | slNode_t *p; 191 | slNode_t *next; 192 | 193 | slNode_t *update[SKIPLIST_MAXLEVEL]; 194 | p = SL_HEAD(sl); 195 | for (i = sl->level - 1; i >= 0; i--) { 196 | while (p->level[i].next != NULL && 197 | sl->comp(p->level[i].next, node, sl, ctx) < 0) { 198 | p = p->level[i].next; 199 | } 200 | update[i] = p; 201 | } 202 | next = p->level[0].next; 203 | if (next != node) { 204 | DLOG("delete error,p=%p,node=%p,next=%p\n", (void *)p, (void *)node, (void *)next); 205 | return -1; 206 | } 207 | p = next; 208 | slDeleteNodeUpdate(sl, p, update); 209 | if (pNode != NULL) 210 | *pNode = p; 211 | else 212 | slFreeNode(p, NULL, NULL); 213 | return 0; 214 | } 215 | 216 | slNode_t * slGetNodeByRank(sl_t *sl, int rank) 217 | { 218 | int traversed = 0; 219 | slNode_t *p; 220 | int i; 221 | p = SL_HEAD(sl); 222 | for (i = sl->level - 1; i >= 0; i--) { 223 | while (p->level[i].next != NULL && p->level[i].span + traversed <= rank) { 224 | traversed += p->level[i].span; 225 | p = p->level[i].next; 226 | } 227 | if (traversed == rank) { 228 | return p; 229 | } 230 | } 231 | return NULL; 232 | } 233 | 234 | int slGetNodesRankRange(sl_t *sl, 235 | int rankMin, int rankMax, 236 | slNode_t **nodeArr, int sz) 237 | { 238 | int n = 0; 239 | slNode_t *p; 240 | SL_FOREACH_RANGE(sl, rankMin, rankMax, p, n) { 241 | nodeArr[n] = p; 242 | if (n + 1 >= sz) 243 | break; 244 | } 245 | return n; 246 | } 247 | 248 | int slGetSize(sl_t *sl) 249 | { 250 | return sl->size; 251 | } 252 | 253 | int slGetRank(sl_t *sl, slNode_t *node, void *ctx) 254 | { 255 | int traversed = 0; 256 | slNode_t *p; 257 | int i; 258 | if (node == NULL) 259 | return 0; 260 | p = SL_HEAD(sl); 261 | for (i = sl->level - 1; i >= 0; i--) { 262 | while (p->level[i].next != NULL && 263 | sl->comp(p->level[i].next, node, sl, ctx) <= 0) { 264 | traversed += p->level[i].span; 265 | p = p->level[i].next; 266 | } 267 | if (sl->comp(p, node, sl, ctx) == 0) { 268 | return traversed; 269 | } 270 | } 271 | return 0; 272 | } 273 | 274 | int slDeleteByRankRange(sl_t *sl, int rankMin, int rankMax, slFreeCb freeCb, void *ctx) 275 | { 276 | slNode_t *update[SKIPLIST_MAXLEVEL], *node; 277 | int traversed = 0; 278 | int removed = 0; 279 | int i; 280 | 281 | assert(1 <= rankMin && rankMin <= rankMax && rankMin <= sl->size); 282 | assert(1 <= rankMax && rankMin <= rankMax && rankMax <= sl->size); 283 | 284 | node = SL_HEAD(sl); 285 | for (i = sl->level-1; i >= 0; i--) { 286 | while (node->level[i].next && (traversed + node->level[i].span) < rankMin) { 287 | traversed += node->level[i].span; 288 | node = node->level[i].next; 289 | } 290 | update[i] = node; 291 | } 292 | 293 | traversed++; 294 | node = node->level[0].next; 295 | while (node && traversed <= rankMax) { 296 | slNode_t *next = node->level[0].next; 297 | slDeleteNode(sl, node, NULL, update); 298 | slFreeNode(node, freeCb, ctx); 299 | removed++; 300 | traversed++; 301 | node = next; 302 | } 303 | return removed; 304 | } 305 | 306 | /** 307 | * greater or equal than score 308 | */ 309 | slNode_t * slFirstGEThan(sl_t *sl, double score) 310 | { 311 | int i; 312 | slNode_t *p; 313 | p = SL_HEAD(sl); 314 | for (i = sl->level - 1; i >= 0; i--) { 315 | while (p->level[i].next != NULL && 316 | p->level[i].next->score < score) { 317 | p = p->level[i].next; 318 | } 319 | } 320 | return p->level[0].next; 321 | } 322 | 323 | /** 324 | * less or equal than score 325 | */ 326 | slNode_t * slLastLEThan(sl_t *sl, double score) 327 | { 328 | int i; 329 | slNode_t *p; 330 | p = SL_HEAD(sl); 331 | for (i = sl->level - 1; i >= 0; i--) { 332 | while (p->level[i].next != NULL && 333 | p->level[i].next->score <= score) { 334 | p = p->level[i].next; 335 | } 336 | } 337 | return p; 338 | } 339 | 340 | -------------------------------------------------------------------------------- /src/skiplist.h: -------------------------------------------------------------------------------- 1 | #ifndef _SKIPLIST_H_IOZX0MYF_ 2 | #define _SKIPLIST_H_IOZX0MYF_ 3 | 4 | #if defined (__cplusplus) 5 | extern "C" { 6 | #endif 7 | 8 | #define SKIPLIST_MAXLEVEL 32 9 | #define SKIPLIST_P 0.25 10 | 11 | #define SL_LVL_NEXT(node, l) ((node)->level[l].next) 12 | #define SL_NEXT(node) ((node)->level[0].next) 13 | #define SL_PREV(node) ((node)->prev) 14 | 15 | #define SL_HEAD(sl) ((slNode_t *)&(sl->head)) 16 | 17 | #define SL_FIRST(sl) (sl->head.level[0].next) 18 | #define SL_LAST(sl) ((slNode_t *)sl->tail) 19 | 20 | #define SL_FOREACH_RANGE(sl, rankMin, rankMax, node, n) \ 21 | for (node = slGetNodeByRank(sl, rankMin), n = 0; \ 22 | node != NULL && n <= rankMax - rankMin; \ 23 | node = SL_NEXT(node), n++) 24 | 25 | #define SL_FOREACH(sl, node) \ 26 | for (node = SL_NEXT(SL_HEAD(sl)); \ 27 | node != NULL; \ 28 | node = SL_NEXT(node)) 29 | 30 | 31 | struct slNode_s; 32 | struct skiplist_s; 33 | 34 | typedef struct slNode_s slNode_t; 35 | typedef struct skiplist_s sl_t; 36 | 37 | typedef void (*slFreeCb)(void *udata, void *ctx); 38 | typedef int (*slCompareCb)(slNode_t *nodeA, slNode_t *nodeB, sl_t *sl, void *ctx); 39 | 40 | struct levelNode_s { 41 | slNode_t *next; 42 | size_t span; 43 | }; 44 | 45 | struct slNode_s { 46 | double score; 47 | void *udata; 48 | slNode_t *prev; 49 | int levelSize; 50 | struct levelNode_s level[1]; 51 | }; 52 | 53 | struct slNodeMax_s { 54 | double score; 55 | void *udata; 56 | slNode_t *prev; 57 | int levelSize; 58 | struct levelNode_s level[SKIPLIST_MAXLEVEL]; 59 | }; 60 | 61 | struct skiplist_s { 62 | struct slNodeMax_s head; 63 | slNode_t *tail; 64 | int level; 65 | size_t size; 66 | slCompareCb comp; 67 | void *udata; 68 | }; 69 | 70 | int slRandomLevel(); 71 | 72 | slNode_t * slCreateNode(int level, void *udata, double score); 73 | void slFreeNode(slNode_t *node, slFreeCb freeCb, void *ctx); 74 | 75 | /** 76 | * you can use slInit to init a struct pointer by yourself 77 | * */ 78 | void slInit(sl_t *sl); 79 | 80 | /** 81 | * just free every node inside of sl, do not free sl; 82 | */ 83 | void slDestroy(sl_t *sl, slFreeCb freeCb, void *ctx); 84 | 85 | /** 86 | * alloc and init sl; 87 | */ 88 | sl_t *slCreate(); 89 | 90 | /** 91 | * slDestroy and free sl; 92 | */ 93 | void slFree(sl_t *sl, slFreeCb freeCb, void *ctx); 94 | 95 | /** 96 | * set your own comp function 97 | */ 98 | slCompareCb slSetCompareCb(sl_t *sl, slCompareCb comp); 99 | 100 | /** 101 | * ctx would be passed to sl->comp function 102 | */ 103 | void slInsertNode(sl_t *sl, slNode_t *node, void *ctx); 104 | 105 | /** 106 | * rank of the node 107 | * ctx would be passed to sl->comp function 108 | */ 109 | int slGetRank(sl_t *sl, slNode_t *node, void *ctx); 110 | 111 | /** 112 | * size of sl 113 | */ 114 | int slGetSize(sl_t *sl); 115 | slNode_t * slGetNodeByRank(sl_t *sl, int rank); 116 | 117 | /** 118 | * delete node, 119 | * return 0 if succeed 120 | * call slFreeNode(node) if pNode == NULL and if node found in sl; 121 | * write &node to pNode if pNode != NULL and if node found in sl, 122 | * you should call slFreeNode by yourself; 123 | */ 124 | int slDeleteNode(sl_t *sl, slNode_t *node, void *ctx, slNode_t **pNode); 125 | 126 | #define slDeleteByRank(sl, rank, freeCb, ctx) slDeleteByRankRange(sl, rank, rank, freeCb, ctx) 127 | 128 | /** 129 | * delete rank range [rankMin, rankMax] 130 | * return deleted count 131 | * ctx would be passed to sl->comp function 132 | */ 133 | int slDeleteByRankRange(sl_t *sl, 134 | int rankMin, int rankMax, 135 | slFreeCb freeCb, void *ctx); 136 | 137 | /** 138 | * greater or equal than score 139 | */ 140 | slNode_t * slFirstGEThan(sl_t *sl, double score); 141 | 142 | /** 143 | * less or equal than score 144 | */ 145 | slNode_t * slLastLEThan(sl_t *sl, double score); 146 | 147 | #if defined (__cplusplus) 148 | } /*end of extern "C"*/ 149 | #endif 150 | 151 | #endif /* end of include guard: _SKIPLIST_H_IOZX0MYF_ */ 152 | 153 | 154 | -------------------------------------------------------------------------------- /test/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../src/skiplist.h" 4 | 5 | #include 6 | 7 | double timenow() 8 | { 9 | struct timeval tm; 10 | gettimeofday(&tm, NULL); 11 | return tm.tv_sec * 1.0 + tm.tv_usec * 1e-6; 12 | } 13 | 14 | int main(int argc, char **argv) 15 | { 16 | int i; 17 | slNode_t *pNode; 18 | sl_t *sl = slCreate(); 19 | int totalSize = 1000000; 20 | 21 | double s; 22 | s = timenow(); 23 | for (i = 0; i < totalSize; i++) { 24 | slNode_t *p = slCreateNode(slRandomLevel(), NULL, rand() % 10000000 * 0.01); 25 | slInsertNode(sl, p, NULL); 26 | } 27 | printf("insert %d time=%f\n", totalSize, timenow() - s); 28 | printf("size of node %lu\n", sizeof(*pNode)); 29 | printf("sl size=%d\n", slGetSize(sl)); 30 | SL_FOREACH_RANGE(sl, 1, 4, pNode, i) { 31 | printf("i=%d, p=%p %lf\n", i, (void *)pNode, pNode->score); 32 | } 33 | 34 | pNode = slGetNodeByRank(sl, 2); 35 | printf("to delete i=2, p=%p %lf\n", (void *)pNode, pNode->score); 36 | printf("rank = %d\n", slGetRank(sl, pNode, NULL)); 37 | slDeleteNode(sl, pNode, NULL, NULL); 38 | SL_FOREACH_RANGE(sl, 1, 5, pNode, i) { 39 | printf("i=%d, p=%p %lf\n", i, (void *)pNode, pNode->score); 40 | } 41 | 42 | s = timenow(); 43 | slDeleteByRankRange(sl, 1, 10000, NULL, NULL); 44 | printf("delete [1, 10000] time=%f\n", timenow() - s); 45 | 46 | s = timenow(); 47 | for (i = 0; i < 10000; i++) { 48 | int rank = rand() % totalSize; 49 | slGetNodeByRank(sl, rank); 50 | } 51 | printf("random slGetNodeByRank [1, 10000] time=%f\n", timenow() - s); 52 | 53 | printf("after delete rank range[2, 3]\n"); 54 | printf("sl size=%d\n", slGetSize(sl)); 55 | SL_FOREACH_RANGE(sl, 1, 5, pNode, i) { 56 | printf("i=%d, p=%p %lf\n", i, (void *)pNode, pNode->score); 57 | } 58 | slFree(sl, NULL, NULL); 59 | return 0; 60 | } 61 | --------------------------------------------------------------------------------