#include "cache.h" #include "mergesort.h" struct mergesort_sublist { void *ptr; unsigned long len; }; static void *get_nth_next(void *list, unsigned long n, void *(*get_next_fn)(const void *)) { while (n-- && list) list = get_next_fn(list); return list; } static void *pop_item(struct mergesort_sublist *l, void *(*get_next_fn)(const void *)) { void *p = l->ptr; l->ptr = get_next_fn(l->ptr); l->len = l->ptr ? (l->len - 1) : 0; return p; } void *llist_mergesort(void *list, void *(*get_next_fn)(const void *), void (*set_next_fn)(void *, void *), int (*compare_fn)(const void *, const void *)) { unsigned long l; if (!list) return NULL; for (l = 1; ; l *= 2) { void *curr; struct mergesort_sublist p, q; p.ptr = list; q.ptr = get_nth_next(p.ptr, l, get_next_fn); if (!q.ptr) break; p.len = q.len = l; if (compare_fn(p.ptr, q.ptr) > 0) list = curr = pop_item(&q, get_next_fn); else list = curr = pop_item(&p, get_next_fn); while (p.ptr) { while (p.len || q.len) { void *prev = curr; if (!p.len) curr = pop_item(&q, get_next_fn); else if (!q.len) curr = pop_item(&p, get_next_fn); else if (compare_fn(p.ptr, q.ptr) > 0) curr = pop_item(&q, get_next_fn); else curr = pop_item(&p, get_next_fn); set_next_fn(prev, curr); } p.ptr = q.ptr; p.len = l; q.ptr = get_nth_next(p.ptr, l, get_next_fn); q.len = q.ptr ? l : 0; } set_next_fn(curr, NULL); } return list; }