Skip to content

Commit 318051e

Browse files
rscharfegitster
authored andcommitted
mergesort: add macros for typed sort of linked lists
Add the macros DECLARE_LIST_SORT and DEFINE_LIST_SORT for building type-specific functions for sorting linked lists. The generated function expects a typed comparison function. The programmer provides full type information (no void pointers). This allows the compiler to check whether the comparison function matches the list type. It can also inline the "next" pointer accessor functions and even the comparison function to get rid of the calling overhead. Also provide a DECLARE_LIST_SORT_DEBUG macro that allows executing custom code whenever the accessor functions are used. It's intended to be used by test-mergesort, which counts these operations. Signed-off-by: René Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 848afeb commit 318051e

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

mergesort.h

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,105 @@ void *llist_mergesort(void *list,
1414
void (*set_next_fn)(void *, void *),
1515
int (*compare_fn)(const void *, const void *));
1616

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+
17118
#endif

0 commit comments

Comments
 (0)