You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
7.7 KiB
297 lines
7.7 KiB
#include <stdio.h>
|
|
#include "skiplist.h"
|
|
|
|
struct skiplist_t{
|
|
skiplist_node_t* header;
|
|
skiplist_size_t size;
|
|
int level;
|
|
skiplist_probability_t probability;
|
|
skiplist_cmp cmp;
|
|
};
|
|
#define SKIPLIST_LEVEL_MAX 32
|
|
struct skiplist_level_t{
|
|
skiplist_node_t* next;
|
|
};
|
|
struct skiplist_node_t{
|
|
void* data;
|
|
skiplist_node_t* prev;
|
|
skiplist_level_t lev[];
|
|
};
|
|
static inline skiplist_node_t* __skiplist_node_create(int level){
|
|
return (skiplist_node_t*)SKIPLIST_ALLOC_MEM(sizeof(skiplist_node_t) + sizeof(skiplist_level_t) * level);
|
|
}
|
|
static inline void __skiplist_node_destroy(skiplist_node_t* node){
|
|
SKIPLIST_FREE_MEM(node);
|
|
}
|
|
static inline int __skiplist_random_level(skiplist_t* sl){
|
|
int level = 1;
|
|
while(SKIPLIST_RAND() >= (RAND_MAX * sl->probability)){
|
|
++ level;
|
|
}
|
|
return (level > SKIPLIST_LEVEL_MAX ? SKIPLIST_LEVEL_MAX : level);
|
|
}
|
|
static inline int
|
|
__skiplist_create(
|
|
skiplist_t** sl,
|
|
skiplist_probability_t probability,
|
|
skiplist_cmp cmp
|
|
){
|
|
skiplist_t* tsl = (skiplist_t*)SKIPLIST_ALLOC_MEM(sizeof(skiplist_t));
|
|
if(tsl == NULL){
|
|
*sl = tsl;
|
|
return SKIPLISTERR_POINTR;
|
|
}
|
|
if((tsl->header = __skiplist_node_create(SKIPLIST_LEVEL_MAX)) == NULL){
|
|
*sl = NULL;
|
|
SKIPLIST_FREE_MEM(tsl);
|
|
return SKIPLISTERR_POINTR;
|
|
}
|
|
tsl->header->prev = tsl->header;
|
|
int i = 0;
|
|
for(;i < SKIPLIST_LEVEL_MAX; ++i){
|
|
tsl->header->lev[i].next = tsl->header;
|
|
}
|
|
tsl->size = 0;
|
|
tsl->level = 1;
|
|
tsl->probability = probability;
|
|
tsl->cmp = cmp;
|
|
*sl = tsl;
|
|
return SKIPLISTOK;
|
|
}
|
|
static inline int
|
|
__skiplist_insert(
|
|
skiplist_t* sl,
|
|
void* key,
|
|
void* data
|
|
){
|
|
skiplist_node_t* level_prev[SKIPLIST_LEVEL_MAX];
|
|
skiplist_node_t *cur = sl->header,*end = sl->header;
|
|
skiplist_node_t* node;
|
|
int i = sl->level - 1,level;
|
|
for(;i >= 0; -- i){
|
|
for(;cur->lev[i].next != end && sl->cmp(key,cur->lev[i].next->data) > 0;cur = cur->lev[i].next);
|
|
level_prev[i] = cur;
|
|
}
|
|
if(cur->lev[0].next != end && sl->cmp(key,cur->lev[0].next->data) == 0){
|
|
return SKIPLISTERR_REEXIST;
|
|
}
|
|
level = __skiplist_random_level(sl);
|
|
if((node = __skiplist_node_create(level)) == NULL){
|
|
return SKIPLISTERR_POINTR;
|
|
}
|
|
node->data = data;
|
|
if(level > sl->level){
|
|
for(i = sl->level;i < level; ++ i){
|
|
level_prev[i] = sl->header;
|
|
}
|
|
sl->level = level;
|
|
}
|
|
for(i = 0;i < level; ++ i){
|
|
node->lev[i].next = level_prev[i]->lev[i].next;
|
|
level_prev[i]->lev[i].next = node;
|
|
}
|
|
node->prev = level_prev[0];
|
|
node->lev[0].next->prev = node;
|
|
++ sl->size;
|
|
return SKIPLISTOK;
|
|
}
|
|
static inline int
|
|
__skiplist_erase(
|
|
skiplist_t* sl,
|
|
void* key,
|
|
void** retdata
|
|
){
|
|
skiplist_node_t* level_prev[SKIPLIST_LEVEL_MAX];
|
|
skiplist_node_t *cur = sl->header,*end = sl->header;
|
|
skiplist_node_t* node;
|
|
int i = sl->level - 1;
|
|
for(;i >= 0; -- i){
|
|
for(;cur->lev[i].next != end && sl->cmp(key,cur->lev[i].next->data) > 0;cur = cur->lev[i].next);
|
|
level_prev[i] = cur;
|
|
}
|
|
if(cur->lev[0].next == end || sl->cmp(key,cur->lev[0].next->data) < 0){
|
|
return SKIPLISTERR_NOEXIST;
|
|
}
|
|
cur = cur->lev[0].next;
|
|
node = cur;
|
|
for(i = 0;i < sl->level; ++i){
|
|
if(level_prev[i]->lev[i].next == node){
|
|
level_prev[i]->lev[i].next = node->lev[i].next;
|
|
}
|
|
}
|
|
node->lev[0].next->prev = node->prev;
|
|
for(;sl->level > 1 && sl->header->lev[sl->level - 1].next == end; -- sl->level);
|
|
if(retdata != NULL){
|
|
*retdata = node->data;
|
|
}
|
|
__skiplist_node_destroy(node);
|
|
-- sl->size;
|
|
return SKIPLISTOK;
|
|
}
|
|
static inline int
|
|
__skiplist_exist(
|
|
skiplist_t* sl,
|
|
void* key,
|
|
void** retdata
|
|
){
|
|
skiplist_node_t *cur = sl->header,*end = sl->header;
|
|
int i = sl->level - 1;
|
|
for(;i >= 0; -- i){
|
|
for(;cur->lev[i].next != end && sl->cmp(key,cur->lev[i].next->data) > 0;cur = cur->lev[i].next);
|
|
}
|
|
if(cur->lev[0].next != end && sl->cmp(key,cur->lev[0].next->data) == 0){
|
|
if(retdata != NULL){
|
|
*retdata = cur->lev[0].next->data;
|
|
}
|
|
return SKIPLISTOK_EXIST;
|
|
}
|
|
return SKIPLISTERR_NOEXIST;
|
|
}
|
|
static inline int
|
|
__skiplist_update(
|
|
skiplist_t* sl,
|
|
void* oldkey,
|
|
void* newkey,
|
|
void* newdata,
|
|
void** retdata
|
|
){
|
|
skiplist_node_t* level_prev[SKIPLIST_LEVEL_MAX];
|
|
skiplist_node_t *cur = sl->header,*node,*end = sl->header;
|
|
int i = sl->level - 1;
|
|
for(;i >= 0; -- i){
|
|
for(;cur->lev[i].next != end && sl->cmp(oldkey,cur->lev[i].next->data) > 0;cur = cur->lev[i].next);
|
|
level_prev[i] = cur;
|
|
}
|
|
if(cur->lev[0].next != end && sl->cmp(oldkey,cur->lev[0].next->data) == 0){
|
|
cur = cur->lev[0].next;
|
|
if((cur->prev != end && sl->cmp(newkey,cur->prev->data) == 0) ||
|
|
(cur->lev[0].next != end && sl->cmp(newkey,cur->lev[0].next->data) == 0)){
|
|
return SKIPLISTERR_REEXIST;
|
|
}
|
|
if(sl->cmp(newkey,cur->data) == 0){
|
|
if(retdata != NULL){
|
|
*retdata = cur->data;
|
|
}
|
|
cur->data = newdata;
|
|
}
|
|
else{
|
|
node = cur;
|
|
for(i = 0;i < sl->level; ++ i){
|
|
if(level_prev[i]->lev[i].next == node){
|
|
level_prev[i]->lev[i].next = node->lev[i].next;
|
|
}
|
|
}
|
|
node->lev[0].next->prev = node->prev;
|
|
for(;sl->level > 1 && sl->header->lev[sl->level - 1].next == end; -- sl->level);
|
|
if(retdata != NULL){
|
|
*retdata = node->data;
|
|
}
|
|
__skiplist_node_destroy(node);
|
|
-- sl->size;
|
|
return __skiplist_insert(sl,newkey,newdata);
|
|
}
|
|
return SKIPLISTOK;
|
|
}
|
|
return SKIPLISTERR_NOEXIST;
|
|
}
|
|
|
|
int skiplist_create(skiplist_t** sl,skiplist_probability_t probability,skiplist_cmp cmp){
|
|
if(sl == NULL || probability <= 1e-6 || probability - 1 >= 1e-6 || cmp == NULL){
|
|
return SKIPLISTERR_PARAM;
|
|
}
|
|
return __skiplist_create(sl,probability,cmp);
|
|
}
|
|
int skiplist_size(skiplist_t* sl,skiplist_size_t* size){
|
|
if(sl == NULL || size == NULL){
|
|
*size = 0;
|
|
return SKIPLISTERR_PARAM;
|
|
}
|
|
*size = sl->size;
|
|
return SKIPLISTOK;
|
|
}
|
|
int skiplist_getcmp(skiplist_t* sl,skiplist_cmp* cmp){
|
|
if(sl == NULL || cmp == NULL){
|
|
return SKIPLISTERR_PARAM;
|
|
}
|
|
*cmp = sl->cmp;
|
|
return SKIPLISTOK;
|
|
}
|
|
int skiplist_insert(skiplist_t* sl,void* key,void* data){
|
|
if(sl == NULL || key == NULL || data == NULL){
|
|
return SKIPLISTERR_PARAM;
|
|
}
|
|
return __skiplist_insert(sl,key,data);
|
|
}
|
|
int skiplist_erase(skiplist_t* sl,void* key,void** retdata){
|
|
if(sl == NULL || key == NULL){
|
|
return SKIPLISTERR_PARAM;
|
|
}
|
|
return __skiplist_erase(sl,key,retdata);
|
|
}
|
|
int skiplist_exist(skiplist_t* sl,void* key,void** retdata){
|
|
if(sl == NULL || key == NULL){
|
|
return SKIPLISTERR_PARAM;
|
|
}
|
|
return __skiplist_exist(sl,key,retdata);
|
|
}
|
|
int skiplist_update(skiplist_t* sl,void* oldkey,void* newkey,void* newdata,void** retdata){
|
|
if(sl == NULL || oldkey == NULL || newkey == NULL || newdata == NULL){
|
|
return SKIPLISTERR_PARAM;
|
|
}
|
|
return __skiplist_update(sl,oldkey,newkey,newdata,retdata);
|
|
}
|
|
int skiplist_destroy(skiplist_t** sl){
|
|
if(sl == NULL || *sl == NULL){
|
|
return SKIPLISTERR_PARAM;
|
|
}
|
|
skiplist_node_t *cur = (*sl)->header,*tmp,*end = (*sl)->header;
|
|
for( ;cur != end; cur = tmp){
|
|
tmp = cur->lev[0].next;
|
|
__skiplist_node_destroy(cur);
|
|
}
|
|
SKIPLIST_FREE_MEM(*sl);
|
|
*sl = NULL;
|
|
return SKIPLISTOK;
|
|
}
|
|
int skiplist_begin(skiplist_t* sl,skiplist_iterator_t* it){
|
|
int ret = SKIPLISTERR_PARAM;
|
|
if(sl == NULL || it == NULL){
|
|
return ret;
|
|
}
|
|
if((ret = skiplist_iterator_create(it)) == SKIPLISTOK){
|
|
*it = sl->header->lev[0].next;
|
|
}
|
|
return ret;
|
|
}
|
|
int skiplist_end(skiplist_t* sl,skiplist_iterator_t* it){
|
|
int ret = SKIPLISTERR_PARAM;
|
|
if(sl == NULL || it == NULL){
|
|
return ret;
|
|
}
|
|
if((ret = skiplist_iterator_create(it)) == SKIPLISTOK){
|
|
*it = sl->header;
|
|
}
|
|
return ret;
|
|
}
|
|
int skiplist_iterator_create(skiplist_iterator_t* it){
|
|
return SKIPLISTOK;
|
|
}
|
|
int skiplist_iterator_equal(skiplist_iterator_t* it1,skiplist_iterator_t* it2){
|
|
return ((*it1) == (*it2));
|
|
}
|
|
void skiplist_iterator_assign(skiplist_iterator_t* dit,const skiplist_iterator_t* sit){
|
|
(*dit) = (*sit);
|
|
}
|
|
const void* skiplist_iterator_value(skiplist_iterator_t* it){
|
|
return (*it)->data;
|
|
}
|
|
void skiplist_iterator_next(skiplist_iterator_t* it){
|
|
(*it) = (*it)->lev[0].next;
|
|
}
|
|
void skiplist_iterator_prev(skiplist_iterator_t* it){
|
|
(*it) = (*it)->prev;
|
|
}
|
|
void skiplist_iterator_destroy(skiplist_iterator_t* it){
|
|
;
|
|
}
|