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.
84 lines
2.0 KiB
84 lines
2.0 KiB
#include "cache.h" |
|
#include "mergesort.h" |
|
|
|
/* Combine two sorted lists. Take from `list` on equality. */ |
|
static void *llist_merge(void *list, void *other, |
|
void *(*get_next_fn)(const void *), |
|
void (*set_next_fn)(void *, void *), |
|
int (*compare_fn)(const void *, const void *)) |
|
{ |
|
void *result = list, *tail; |
|
|
|
if (compare_fn(list, other) > 0) { |
|
result = other; |
|
goto other; |
|
} |
|
for (;;) { |
|
do { |
|
tail = list; |
|
list = get_next_fn(list); |
|
if (!list) { |
|
set_next_fn(tail, other); |
|
return result; |
|
} |
|
} while (compare_fn(list, other) <= 0); |
|
set_next_fn(tail, other); |
|
other: |
|
do { |
|
tail = other; |
|
other = get_next_fn(other); |
|
if (!other) { |
|
set_next_fn(tail, list); |
|
return result; |
|
} |
|
} while (compare_fn(list, other) > 0); |
|
set_next_fn(tail, list); |
|
} |
|
} |
|
|
|
/* |
|
* Perform an iterative mergesort using an array of sublists. |
|
* |
|
* n is the number of items. |
|
* ranks[i] is undefined if n & 2^i == 0, and assumed empty. |
|
* ranks[i] contains a sublist of length 2^i otherwise. |
|
* |
|
* The number of bits in a void pointer limits the number of objects |
|
* that can be created, and thus the number of array elements necessary |
|
* to be able to sort any valid list. |
|
* |
|
* Adding an item to this array is like incrementing a binary number; |
|
* positional values for set bits correspond to sublist lengths. |
|
*/ |
|
void *llist_mergesort(void *list, |
|
void *(*get_next_fn)(const void *), |
|
void (*set_next_fn)(void *, void *), |
|
int (*compare_fn)(const void *, const void *)) |
|
{ |
|
void *ranks[bitsizeof(void *)]; |
|
size_t n = 0; |
|
int i; |
|
|
|
while (list) { |
|
void *next = get_next_fn(list); |
|
if (next) |
|
set_next_fn(list, NULL); |
|
for (i = 0; n & ((size_t)1 << i); i++) |
|
list = llist_merge(ranks[i], list, get_next_fn, |
|
set_next_fn, compare_fn); |
|
n++; |
|
ranks[i] = list; |
|
list = next; |
|
} |
|
|
|
for (i = 0; n; i++, n >>= 1) { |
|
if (!(n & 1)) |
|
continue; |
|
if (list) |
|
list = llist_merge(ranks[i], list, get_next_fn, |
|
set_next_fn, compare_fn); |
|
else |
|
list = ranks[i]; |
|
} |
|
return list; |
|
}
|
|
|