]> git.ipfire.org Git - thirdparty/git.git/blame - mergesort.h
mergesort: add macros for typed sort of linked lists
[thirdparty/git.git] / mergesort.h
CommitLineData
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 */
12void *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) \
19static 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) \
59scope 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) \
93scope 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 \
99static inline type *name##__get_next(const type *elem) \
100{ \
101 on_get_next; \
102 return elem->next_member; \
103} \
104 \
105static inline void name##__set_next(type *elem, type *next) \
106{ \
107 on_set_next; \
108 elem->next_member = next; \
109} \
110 \
111DEFINE_LIST_MERGE_INTERNAL(name, type) \
112DEFINE_LIST_SORT_INTERNAL(scope, name, type) \
113DECLARE_LIST_SORT(scope, name, type)
114
115#define DEFINE_LIST_SORT(scope, name, type, next_member) \
116DEFINE_LIST_SORT_DEBUG(scope, name, type, next_member, (void)0, (void)0)
117
0db71e0f 118#endif