diff --git a/common/list.c b/common/list.c index 66d52f700..bd9abcd82 100644 --- a/common/list.c +++ b/common/list.c @@ -147,3 +147,61 @@ void list_stable_sort(list_t *list, int compare(const void *a, const void *b)) { list_inplace_sort(list, 0, list->length - 1, compare); } } + +void list_sortedset_insert(list_t *list, void *item, + int compare(const void *item_left, const void *item_right), + void *replace(void *old_item, void* new_item)) { + if (list->length <= 0) { + list_add(list, item); + return; + } + + size_t lower = 0; + size_t upper = (size_t)list->length - 1; + while (lower <= upper && upper != (size_t)-1) { + size_t div = (lower + upper) / 2; + int cv = compare(list->items[div], item); + if (cv < 0) { + lower = div + 1; + } else if (cv > 0) { + upper = div - 1; + } else { + list->items[div] = replace(list->items[div], item); + return; + } + } + list_insert(list, lower, item); +} + +int list_sortedset_find(list_t *list, + int compare(const void *item, const void *cmp_to), + const void *cmp_to) { + if (list->length <= 0) { + return -1; + } + + size_t lower = 0; + size_t upper = (size_t)list->length - 1; + while (lower <= upper && upper != (size_t)-1) { + size_t div = (lower + upper) / 2; + int cv = compare(list->items[div], cmp_to); + if (cv < 0) { + lower = div + 1; + } else if (cv > 0) { + upper = div - 1; + } else { + return div; + } + } + return -1; +} + +int list_is_sortedset(list_t *list, + int compare(const void *left, const void *right)) { + for (size_t i = 1; i < (size_t)list->length; i++) { + if (compare(list->items[i - 1], list->items[i]) >= 0) { + return 0; + } + } + return 1; +} diff --git a/include/list.h b/include/list.h index 5a0d7d809..e610bb7e9 100644 --- a/include/list.h +++ b/include/list.h @@ -12,6 +12,12 @@ void list_free(list_t *list); void list_foreach(list_t *list, void (*callback)(void* item)); void list_add(list_t *list, void *item); void list_insert(list_t *list, int index, void *item); +// Insert an item into the list which is already sorted strictly ascending +// according to 'compare'. 'replace' is called when displacing an old item +// and returns the item which will take its place. +void list_sortedset_insert(list_t *list, void* item, + int compare(const void *item_left, const void *item_right), + void *replace(void *old_item, void* new_item)); void list_del(list_t *list, int index); void list_cat(list_t *list, list_t *source); // See qsort. Remember to use *_qsort functions as compare functions, @@ -20,6 +26,11 @@ void list_qsort(list_t *list, int compare(const void *left, const void *right)); // Return index for first item in list that returns 0 for given compare // function or -1 if none matches. int list_seq_find(list_t *list, int compare(const void *item, const void *cmp_to), const void *cmp_to); +// Requires a list sorted strictly ascending according to 'compare'; +// returns the index of the matching item, or -1 is no such item exists +int list_sortedset_find(list_t *list, int compare(const void *item, const void *cmp_to), const void *cmp_to); +// Check if a list is sorted strictly ascending according to compare +int list_is_sortedset(list_t *list, int compare(const void *left, const void *right)); // stable sort since qsort is not guaranteed to be stable void list_stable_sort(list_t *list, int compare(const void *a, const void *b)); // swap two elements in a list