]>
Commit | Line | Data |
---|---|---|
0db71e0f RS |
1 | #ifndef MERGESORT_H |
2 | #define MERGESORT_H | |
3 | ||
7365c95d JH |
4 | /* |
5 | * Sort linked list in place. | |
6 | * - get_next_fn() returns the next element given an element of a linked list. | |
7 | * - set_next_fn() takes two elements A and B, and makes B the "next" element | |
8 | * of A on the list. | |
9 | * - compare_fn() takes two elements A and B, and returns negative, 0, positive | |
10 | * as the same sign as "subtracting" B from A. | |
11 | */ | |
12 | void *llist_mergesort(void *list, | |
13 | void *(*get_next_fn)(const void *), | |
14 | void (*set_next_fn)(void *, void *), | |
15 | int (*compare_fn)(const void *, const void *)); | |
0db71e0f | 16 | |
318051ea RS |
17 | /* Combine two sorted lists. Take from `list` on equality. */ |
18 | #define DEFINE_LIST_MERGE_INTERNAL(name, type) \ | |
19 | static type *name##__merge(type *list, type *other, \ | |
20 | int (*compare_fn)(const type *, const type *))\ | |
21 | { \ | |
22 | type *result = list, *tail; \ | |
23 | int prefer_list = compare_fn(list, other) <= 0; \ | |
24 | \ | |
25 | if (!prefer_list) { \ | |
26 | result = other; \ | |
27 | SWAP(list, other); \ | |
28 | } \ | |
29 | for (;;) { \ | |
30 | do { \ | |
31 | tail = list; \ | |
32 | list = name##__get_next(list); \ | |
33 | if (!list) { \ | |
34 | name##__set_next(tail, other); \ | |
35 | return result; \ | |
36 | } \ | |
37 | } while (compare_fn(list, other) < prefer_list); \ | |
38 | name##__set_next(tail, other); \ | |
39 | prefer_list ^= 1; \ | |
40 | SWAP(list, other); \ | |
41 | } \ | |
42 | } | |
43 | ||
44 | /* | |
45 | * Perform an iterative mergesort using an array of sublists. | |
46 | * | |
47 | * n is the number of items. | |
48 | * ranks[i] is undefined if n & 2^i == 0, and assumed empty. | |
49 | * ranks[i] contains a sublist of length 2^i otherwise. | |
50 | * | |
51 | * The number of bits in a void pointer limits the number of objects | |
52 | * that can be created, and thus the number of array elements necessary | |
53 | * to be able to sort any valid list. | |
54 | * | |
55 | * Adding an item to this array is like incrementing a binary number; | |
56 | * positional values for set bits correspond to sublist lengths. | |
57 | */ | |
58 | #define DEFINE_LIST_SORT_INTERNAL(scope, name, type) \ | |
59 | scope void name(type **listp, \ | |
60 | int (*compare_fn)(const type *, const type *)) \ | |
61 | { \ | |
62 | type *list = *listp; \ | |
63 | type *ranks[bitsizeof(type *)]; \ | |
64 | size_t n = 0; \ | |
65 | \ | |
66 | if (!list) \ | |
67 | return; \ | |
68 | \ | |
69 | for (;;) { \ | |
70 | int i; \ | |
71 | size_t m; \ | |
72 | type *next = name##__get_next(list); \ | |
73 | if (next) \ | |
74 | name##__set_next(list, NULL); \ | |
75 | for (i = 0, m = n;; i++, m >>= 1) { \ | |
76 | if (m & 1) { \ | |
77 | list = name##__merge(ranks[i], list, \ | |
78 | compare_fn); \ | |
79 | } else if (next) { \ | |
80 | break; \ | |
81 | } else if (!m) { \ | |
82 | *listp = list; \ | |
83 | return; \ | |
84 | } \ | |
85 | } \ | |
86 | n++; \ | |
87 | ranks[i] = list; \ | |
88 | list = next; \ | |
89 | } \ | |
90 | } | |
91 | ||
92 | #define DECLARE_LIST_SORT(scope, name, type) \ | |
93 | scope void name(type **listp, \ | |
94 | int (*compare_fn)(const type *, const type *)) | |
95 | ||
96 | #define DEFINE_LIST_SORT_DEBUG(scope, name, type, next_member, \ | |
97 | on_get_next, on_set_next) \ | |
98 | \ | |
99 | static inline type *name##__get_next(const type *elem) \ | |
100 | { \ | |
101 | on_get_next; \ | |
102 | return elem->next_member; \ | |
103 | } \ | |
104 | \ | |
105 | static inline void name##__set_next(type *elem, type *next) \ | |
106 | { \ | |
107 | on_set_next; \ | |
108 | elem->next_member = next; \ | |
109 | } \ | |
110 | \ | |
111 | DEFINE_LIST_MERGE_INTERNAL(name, type) \ | |
112 | DEFINE_LIST_SORT_INTERNAL(scope, name, type) \ | |
113 | DECLARE_LIST_SORT(scope, name, type) | |
114 | ||
115 | #define DEFINE_LIST_SORT(scope, name, type, next_member) \ | |
116 | DEFINE_LIST_SORT_DEBUG(scope, name, type, next_member, (void)0, (void)0) | |
117 | ||
0db71e0f | 118 | #endif |