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.
73 lines
1.5 KiB
73 lines
1.5 KiB
#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; |
|
}
|
|
|