skiplist support stable sort

pull/5/head
yuqing 2015-12-25 19:02:36 +08:00
parent 159d69983b
commit a6ef605c6e
4 changed files with 124 additions and 20 deletions

View File

@ -1,7 +1,7 @@
Version 1.24 2015-12-25
* php extension compiled on PHP 7
* add skiplist
* add skiplist which support stable sort
* make.sh: use sed to replace perl
Version 1.23 2015-11-16

View File

@ -18,11 +18,12 @@
#include "skiplist.h"
int skiplist_init_ex(Skiplist *sl, const int level_count,
skiplist_compare_func compare_func, const int alloc_elements_once)
skiplist_compare_func compare_func, const int min_alloc_elements_once)
{
int bytes;
int element_size;
int i;
int alloc_elements_once;
int result;
struct fast_mblock_man *top_mblock;
@ -33,7 +34,7 @@ int skiplist_init_ex(Skiplist *sl, const int level_count,
return EINVAL;
}
if (level_count > 32) {
if (level_count > 20) {
logError("file: "__FILE__", line: %d, "
"level count: %d is too large",
__LINE__, level_count);
@ -50,13 +51,24 @@ int skiplist_init_ex(Skiplist *sl, const int level_count,
}
memset(sl->mblocks, 0, bytes);
for (i=0; i<level_count; i++) {
alloc_elements_once = min_alloc_elements_once;
if (alloc_elements_once <= 0) {
alloc_elements_once = SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE;
}
else if (alloc_elements_once > 1024) {
alloc_elements_once = 1024;
}
for (i=level_count-1; i>=0; i--) {
element_size = sizeof(SkiplistNode) + sizeof(SkiplistNode *) * (i + 1);
if ((result=fast_mblock_init_ex(sl->mblocks + i,
element_size, alloc_elements_once, NULL, false)) != 0)
{
return result;
}
if (alloc_elements_once < 1024 * 1024) {
alloc_elements_once *= 2;
}
}
sl->top_level_index = level_count - 1;
@ -67,6 +79,17 @@ int skiplist_init_ex(Skiplist *sl, const int level_count,
}
memset(sl->top, 0, top_mblock->info.element_size);
sl->tail = (SkiplistNode *)fast_mblock_alloc_object(sl->mblocks + 0);
if (sl->tail == NULL) {
return ENOMEM;
}
memset(sl->tail, 0, sl->mblocks[0].info.element_size);
sl->tail->prev = sl->top;
for (i=0; i<level_count; i++) {
sl->top->links[i] = sl->tail;
}
sl->level_count = level_count;
sl->compare_func = compare_func;
@ -109,7 +132,7 @@ int skiplist_insert(Skiplist *sl, void *data)
int level_index;
SkiplistNode *node;
SkiplistNode *previous;
SkiplistNode *current;
SkiplistNode *current = NULL;
level_index = skiplist_get_level_index(sl);
node = (SkiplistNode *)fast_mblock_alloc_object(sl->mblocks + level_index);
@ -119,16 +142,16 @@ int skiplist_insert(Skiplist *sl, void *data)
previous = sl->top;
for (i=sl->top_level_index; i>level_index; i--) {
while (previous->links[i] != NULL && sl->compare_func(data,
previous->links[i]->data) > 0)
while (previous->links[i] != sl->tail && sl->compare_func(data,
previous->links[i]->data) < 0)
{
previous = previous->links[i];
}
}
while (i >= 0) {
while (previous->links[i] != NULL && sl->compare_func(data,
previous->links[i]->data) > 0)
while (previous->links[i] != sl->tail && sl->compare_func(data,
previous->links[i]->data) < 0)
{
previous = previous->links[i];
}
@ -140,6 +163,8 @@ int skiplist_insert(Skiplist *sl, void *data)
i--;
}
node->prev = previous;
current->prev = node;
node->data = data;
return 0;
}
@ -155,9 +180,9 @@ static SkiplistNode *skiplist_get_previous(Skiplist *sl, void *data,
found = NULL;
previous = sl->top;
for (i=sl->top_level_index; i>=0; i--) {
while (previous->links[i] != NULL) {
while (previous->links[i] != sl->tail) {
cmp = sl->compare_func(data, previous->links[i]->data);
if (cmp < 0) {
if (cmp > 0) {
break;
}
else if (cmp == 0) {
@ -188,8 +213,8 @@ int skiplist_delete(Skiplist *sl, void *data)
deleted = previous->links[level_index];
for (i=level_index; i>=0; i--) {
while (previous->links[i] != NULL && sl->compare_func(data,
previous->links[i]->data) > 0)
while (previous->links[i] != sl->tail && sl->compare_func(data,
previous->links[i]->data) < 0)
{
previous = previous->links[i];
}
@ -198,6 +223,8 @@ int skiplist_delete(Skiplist *sl, void *data)
previous->links[i] = previous->links[i]->links[i];
}
deleted->links[0]->prev = previous;
fast_mblock_free_object(sl->mblocks + level_index, deleted);
return 0;
}

View File

@ -6,7 +6,7 @@
* Please visit the FastDFS Home Page http://www.csource.org/ for more detail.
**/
//skiplist.h
//skiplist.h, support stable sort :)
#ifndef _SKIPLIST_H
#define _SKIPLIST_H
@ -21,7 +21,7 @@ typedef int (*skiplist_compare_func)(const void *p1, const void *p2);
typedef struct skiplist_node
{
void *data;
// struct skiplist_node *prev; //for stable sort
struct skiplist_node *prev; //for stable sort
struct skiplist_node *links[0];
} SkiplistNode;
@ -32,9 +32,11 @@ typedef struct skiplist
skiplist_compare_func compare_func;
struct fast_mblock_man *mblocks; //node allocators
SkiplistNode *top; //the top node
SkiplistNode *tail; //the tail node for interator
} Skiplist;
typedef struct skiplist_iterator {
Skiplist *sl;
SkiplistNode *current;
} SkiplistIterator;
@ -42,11 +44,14 @@ typedef struct skiplist_iterator {
extern "C" {
#endif
#define SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE 128
#define skiplist_init(sl, level_count, compare_func) \
skiplist_init_ex(sl, level_count, compare_func, 1024)
skiplist_init_ex(sl, level_count, compare_func, \
SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE)
int skiplist_init_ex(Skiplist *sl, const int level_count,
skiplist_compare_func compare_func, const int alloc_elements_once);
skiplist_compare_func compare_func, const int min_alloc_elements_once);
void skiplist_destroy(Skiplist *sl);
@ -56,19 +61,20 @@ void *skiplist_find(Skiplist *sl, void *data);
static inline void skiplist_iterator(Skiplist *sl, SkiplistIterator *iterator)
{
iterator->current = sl->top->links[0];
iterator->sl = sl;
iterator->current = sl->tail->prev;
}
static inline void *skiplist_next(SkiplistIterator *iterator)
{
void *data;
if (iterator->current == NULL) {
if (iterator->current == iterator->sl->top) {
return NULL;
}
data = iterator->current->data;
iterator->current = iterator->current->links[0];
iterator->current = iterator->current->prev;
return data;
}

View File

@ -91,6 +91,72 @@ static void test_delete()
assert(i==0);
}
typedef struct record
{
int line;
int key;
} Record;
static int compare_record(const void *p1, const void *p2)
{
return ((Record *)p1)->key - ((Record *)p2)->key;
}
static int test_stable_sort()
{
#define RECORDS 20
int i;
int result;
int index1;
int index2;
Skiplist sl;
SkiplistIterator iterator;
Record records[RECORDS];
Record *record;
void *value;
result = skiplist_init_ex(&sl, 16, compare_record, 128);
if (result != 0) {
return result;
}
for (i=0; i<RECORDS; i++) {
records[i].line = i + 1;
records[i].key = i + 1;
}
for (i=0; i<RECORDS/4; i++) {
index1 = (RECORDS - 1) * (int64_t)rand() / (int64_t)RAND_MAX;
index2 = RECORDS - 1 - index1;
if (index1 != index2) {
records[index1].key = records[index2].key;
}
}
for (i=0; i<RECORDS; i++) {
if ((result=skiplist_insert(&sl, records + i)) != 0) {
return result;
}
}
for (i=0; i<RECORDS; i++) {
value = skiplist_find(&sl, records + i);
assert(value != NULL && ((Record *)value)->key == records[i].key);
}
i = 0;
skiplist_iterator(&sl, &iterator);
while ((value=skiplist_next(&iterator)) != NULL) {
i++;
record = (Record *)value;
printf("%d => #%d\n", record->key, record->line);
}
assert(i==RECORDS);
skiplist_destroy(&sl);
return 0;
}
int main(int argc, char *argv[])
{
int i;
@ -117,6 +183,7 @@ int main(int argc, char *argv[])
numbers[index2] = tmp;
}
fast_mblock_manager_init();
result = skiplist_init_ex(&sl, 12, compare_func, 128);
if (result != 0) {
return result;
@ -125,6 +192,8 @@ int main(int argc, char *argv[])
test_insert();
printf("\n");
fast_mblock_manager_stat_print(false);
test_delete();
printf("\n");
@ -135,6 +204,8 @@ int main(int argc, char *argv[])
printf("\n");
skiplist_destroy(&sl);
test_stable_sort();
printf("pass OK\n");
return 0;
}