diff --git a/src/multi_skiplist.c b/src/multi_skiplist.c index eaa47e6..15cc32c 100644 --- a/src/multi_skiplist.c +++ b/src/multi_skiplist.c @@ -18,7 +18,8 @@ #include "multi_skiplist.h" int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count, - multi_skiplist_compare_func compare_func, const int min_alloc_elements_once) + multi_skiplist_compare_func compare_func, + const int min_alloc_elements_once) { int bytes; int element_size; @@ -223,7 +224,7 @@ int multi_skiplist_insert(MultiSkiplist *sl, void *data) } int multi_skiplist_do_delete(MultiSkiplist *sl, void *data, - const bool delete_all) + const bool delete_all, int *delete_count) { int i; int level_index; @@ -232,6 +233,7 @@ int multi_skiplist_do_delete(MultiSkiplist *sl, void *data, MultiSkiplistData *dataNode; MultiSkiplistData *dataCurrent; + *delete_count = 0; previous = multi_skiplist_get_previous(sl, data, &level_index); if (previous == NULL) { return ENOENT; @@ -243,6 +245,7 @@ int multi_skiplist_do_delete(MultiSkiplist *sl, void *data, dataNode = deleted->head; deleted->head = dataNode->next; fast_mblock_free_object(&sl->data_mblock, dataNode); + *delete_count = 1; return 0; } } @@ -261,6 +264,8 @@ int multi_skiplist_do_delete(MultiSkiplist *sl, void *data, while (dataCurrent != NULL) { dataNode = dataCurrent; dataCurrent = dataCurrent->next; + + (*delete_count)++; fast_mblock_free_object(&sl->data_mblock, dataNode); } @@ -270,12 +275,13 @@ int multi_skiplist_do_delete(MultiSkiplist *sl, void *data, int multi_skiplist_delete(MultiSkiplist *sl, void *data) { - return multi_skiplist_do_delete(sl, data, false); + int delete_count; + return multi_skiplist_do_delete(sl, data, false, &delete_count); } -int multi_skiplist_delete_all(MultiSkiplist *sl, void *data) +int multi_skiplist_delete_all(MultiSkiplist *sl, void *data, int *delete_count) { - return multi_skiplist_do_delete(sl, data, true); + return multi_skiplist_do_delete(sl, data, true, delete_count); } void *multi_skiplist_find(MultiSkiplist *sl, void *data) @@ -287,3 +293,23 @@ void *multi_skiplist_find(MultiSkiplist *sl, void *data) return (previous != NULL) ? previous->links[level_index]->head->data : NULL; } +int multi_skiplist_find_all(MultiSkiplist *sl, void *data, + MultiSkiplistIterator *iterator) +{ + int level_index; + MultiSkiplistNode *previous; + + iterator->current.data = NULL; + previous = multi_skiplist_get_previous(sl, data, &level_index); + if (previous == NULL) { + iterator->current.node = sl->tail; + iterator->tail = sl->tail; + return ENOENT; + } + else { + iterator->current.node = previous; + iterator->tail = previous->links[0]->links[0]; + return 0; + } +} + diff --git a/src/multi_skiplist.h b/src/multi_skiplist.h index f563123..30249e5 100644 --- a/src/multi_skiplist.h +++ b/src/multi_skiplist.h @@ -43,7 +43,7 @@ typedef struct multi_skiplist } MultiSkiplist; typedef struct multi_skiplist_iterator { - MultiSkiplist *sl; + MultiSkiplistNode *tail; struct { MultiSkiplistNode *node; MultiSkiplistData *data; @@ -61,18 +61,22 @@ extern "C" { SKIPLIST_DEFAULT_MIN_ALLOC_ELEMENTS_ONCE) int multi_skiplist_init_ex(MultiSkiplist *sl, const int level_count, - multi_skiplist_compare_func compare_func, const int min_alloc_elements_once); + multi_skiplist_compare_func compare_func, + const int min_alloc_elements_once); void multi_skiplist_destroy(MultiSkiplist *sl); int multi_skiplist_insert(MultiSkiplist *sl, void *data); int multi_skiplist_delete(MultiSkiplist *sl, void *data); -int multi_skiplist_delete_all(MultiSkiplist *sl, void *data); +int multi_skiplist_delete_all(MultiSkiplist *sl, void *data, int *delete_count); void *multi_skiplist_find(MultiSkiplist *sl, void *data); +int multi_skiplist_find_all(MultiSkiplist *sl, void *data, + MultiSkiplistIterator *iterator); -static inline void multi_skiplist_iterator(MultiSkiplist *sl, MultiSkiplistIterator *iterator) +static inline void multi_skiplist_iterator(MultiSkiplist *sl, + MultiSkiplistIterator *iterator) { - iterator->sl = sl; + iterator->tail = sl->tail; iterator->current.node = sl->top; iterator->current.data = NULL; } @@ -82,8 +86,8 @@ static inline void *multi_skiplist_next(MultiSkiplistIterator *iterator) void *data; if (iterator->current.data == NULL) { - if (iterator->current.node == iterator->sl->tail || - iterator->current.node->links[0] == iterator->sl->tail) + if (iterator->current.node == iterator->tail || + iterator->current.node->links[0] == iterator->tail) { return NULL; } diff --git a/src/skiplist.c b/src/skiplist.c index f77ff71..1377e67 100644 --- a/src/skiplist.c +++ b/src/skiplist.c @@ -229,6 +229,16 @@ int skiplist_delete(Skiplist *sl, void *data) return 0; } +int skiplist_delete_all(Skiplist *sl, void *data, int *delete_count) +{ + *delete_count = 0; + while (skiplist_delete(sl, data) == 0) { + (*delete_count)++; + } + + return *delete_count > 0 ? 0 : ENOENT; +} + void *skiplist_find(Skiplist *sl, void *data) { int level_index; @@ -238,3 +248,26 @@ void *skiplist_find(Skiplist *sl, void *data) return (previous != NULL) ? previous->links[level_index]->data : NULL; } +int skiplist_find_all(Skiplist *sl, void *data, SkiplistIterator *iterator) +{ + int level_index; + SkiplistNode *previous; + SkiplistNode *last; + + previous = skiplist_get_previous(sl, data, &level_index); + if (previous == NULL) { + iterator->top = sl->top; + iterator->current = sl->top; + return ENOENT; + } + + last = previous->links[0]->links[0]; + while (last != sl->tail && sl->compare_func(data, last->data) == 0) { + last = last->links[0]; + } + + iterator->top = previous; + iterator->current = last->prev; + return 0; +} + diff --git a/src/skiplist.h b/src/skiplist.h index 95849ee..6ee80be 100644 --- a/src/skiplist.h +++ b/src/skiplist.h @@ -36,7 +36,7 @@ typedef struct skiplist } Skiplist; typedef struct skiplist_iterator { - Skiplist *sl; + SkiplistNode *top; SkiplistNode *current; } SkiplistIterator; @@ -57,11 +57,13 @@ void skiplist_destroy(Skiplist *sl); int skiplist_insert(Skiplist *sl, void *data); int skiplist_delete(Skiplist *sl, void *data); +int skiplist_delete_all(Skiplist *sl, void *data, int *delete_count); void *skiplist_find(Skiplist *sl, void *data); +int skiplist_find_all(Skiplist *sl, void *data, SkiplistIterator *iterator); static inline void skiplist_iterator(Skiplist *sl, SkiplistIterator *iterator) { - iterator->sl = sl; + iterator->top = sl->top; iterator->current = sl->tail->prev; } @@ -69,7 +71,7 @@ static inline void *skiplist_next(SkiplistIterator *iterator) { void *data; - if (iterator->current == iterator->sl->top) { + if (iterator->current == iterator->top) { return NULL; } diff --git a/src/tests/test_multi_skiplist.c b/src/tests/test_multi_skiplist.c index a0dbf85..64a8039 100644 --- a/src/tests/test_multi_skiplist.c +++ b/src/tests/test_multi_skiplist.c @@ -10,7 +10,7 @@ #include "logger.h" #include "shared_func.h" -#define COUNT 1280000 +#define COUNT 12800 #define LEVEL_COUNT 18 #define MIN_ALLOC_ONCE 32 #define LAST_INDEX (COUNT - 1) @@ -106,15 +106,18 @@ static int compare_record(const void *p1, const void *p2) static int test_stable_sort() { -#define RECORDS 20 +#define RECORDS 32 int i; int result; int index1; int index2; + int delete_count; + int total_delete_count; MultiSkiplist sl; MultiSkiplistIterator iterator; Record records[RECORDS]; Record *record; + Record target; void *value; result = multi_skiplist_init_ex(&sl, 12, compare_record, 128); @@ -153,7 +156,39 @@ static int test_stable_sort() record = (Record *)value; printf("%d => #%d\n", record->key, record->line); } - assert(i==RECORDS); + assert(i == RECORDS); + + target.key = 10; + target.line = 0; + if (multi_skiplist_find_all(&sl, &target, &iterator) == 0) { + printf("found key: %d\n", target.key); + } + i = 0; + while ((value=multi_skiplist_next(&iterator)) != NULL) { + i++; + record = (Record *)value; + printf("%d => #%d\n", record->key, record->line); + } + printf("found record count: %d\n", i); + + total_delete_count = 0; + for (i=0; i 0) || + (result != 0 && delete_count == 0)); + } + assert(total_delete_count == RECORDS); + + i = 0; + multi_skiplist_iterator(&sl, &iterator); + while ((value=multi_skiplist_next(&iterator)) != NULL) { + i++; + } + assert(i == 0); multi_skiplist_destroy(&sl); return 0; diff --git a/src/tests/test_skiplist.c b/src/tests/test_skiplist.c index aca468e..91bc728 100644 --- a/src/tests/test_skiplist.c +++ b/src/tests/test_skiplist.c @@ -10,7 +10,7 @@ #include "logger.h" #include "shared_func.h" -#define COUNT 1000 +#define COUNT 100000 #define LEVEL_COUNT 18 #define MIN_ALLOC_ONCE 32 #define LAST_INDEX (COUNT - 1) @@ -106,15 +106,18 @@ static int compare_record(const void *p1, const void *p2) static int test_stable_sort() { -#define RECORDS 20 +#define RECORDS 32 int i; int result; int index1; int index2; + int delete_count; + int total_delete_count; Skiplist sl; SkiplistIterator iterator; Record records[RECORDS]; Record *record; + Record target; void *value; result = skiplist_init_ex(&sl, 12, compare_record, 128); @@ -155,6 +158,38 @@ static int test_stable_sort() } assert(i==RECORDS); + target.key = 10; + target.line = 0; + if (skiplist_find_all(&sl, &target, &iterator) == 0) { + printf("found key: %d\n", target.key); + } + i = 0; + while ((value=skiplist_next(&iterator)) != NULL) { + i++; + record = (Record *)value; + printf("%d => #%d\n", record->key, record->line); + } + printf("found record count: %d\n", i); + + total_delete_count = 0; + for (i=0; i 0) || + (result != 0 && delete_count == 0)); + } + assert(total_delete_count == RECORDS); + + i = 0; + skiplist_iterator(&sl, &iterator); + while ((value=skiplist_next(&iterator)) != NULL) { + i++; + } + assert(i == 0); + skiplist_destroy(&sl); return 0; }