Skip to content

Commit 4e0d160

Browse files
committed
Merge branch 'rs/mergesort'
Make our mergesort implementation type-safe. * rs/mergesort: mergesort: remove llist_mergesort() packfile: use DEFINE_LIST_SORT fetch-pack: use DEFINE_LIST_SORT commit: use DEFINE_LIST_SORT blame: use DEFINE_LIST_SORT test-mergesort: use DEFINE_LIST_SORT test-mergesort: use DEFINE_LIST_SORT_DEBUG mergesort: add macros for typed sort of linked lists mergesort: tighten merge loop mergesort: unify ranks loops
2 parents 87098a0 + 0f1eb7d commit 4e0d160

File tree

12 files changed

+134
-199
lines changed

12 files changed

+134
-199
lines changed

Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,6 @@ LIB_OBJS += merge-ort.o
992992
LIB_OBJS += merge-ort-wrappers.o
993993
LIB_OBJS += merge-recursive.o
994994
LIB_OBJS += merge.o
995-
LIB_OBJS += mergesort.o
996995
LIB_OBJS += midx.o
997996
LIB_OBJS += name-hash.o
998997
LIB_OBJS += negotiator/default.o

blame.c

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,30 +1098,22 @@ static struct blame_entry *blame_merge(struct blame_entry *list1,
10981098
}
10991099
}
11001100

1101-
static void *get_next_blame(const void *p)
1102-
{
1103-
return ((struct blame_entry *)p)->next;
1104-
}
1105-
1106-
static void set_next_blame(void *p1, void *p2)
1107-
{
1108-
((struct blame_entry *)p1)->next = p2;
1109-
}
1101+
DEFINE_LIST_SORT(static, sort_blame_entries, struct blame_entry, next);
11101102

11111103
/*
11121104
* Final image line numbers are all different, so we don't need a
11131105
* three-way comparison here.
11141106
*/
11151107

1116-
static int compare_blame_final(const void *p1, const void *p2)
1108+
static int compare_blame_final(const struct blame_entry *e1,
1109+
const struct blame_entry *e2)
11171110
{
1118-
return ((struct blame_entry *)p1)->lno > ((struct blame_entry *)p2)->lno
1119-
? 1 : -1;
1111+
return e1->lno > e2->lno ? 1 : -1;
11201112
}
11211113

1122-
static int compare_blame_suspect(const void *p1, const void *p2)
1114+
static int compare_blame_suspect(const struct blame_entry *s1,
1115+
const struct blame_entry *s2)
11231116
{
1124-
const struct blame_entry *s1 = p1, *s2 = p2;
11251117
/*
11261118
* to allow for collating suspects, we sort according to the
11271119
* respective pointer value as the primary sorting criterion.
@@ -1138,8 +1130,7 @@ static int compare_blame_suspect(const void *p1, const void *p2)
11381130

11391131
void blame_sort_final(struct blame_scoreboard *sb)
11401132
{
1141-
sb->ent = llist_mergesort(sb->ent, get_next_blame, set_next_blame,
1142-
compare_blame_final);
1133+
sort_blame_entries(&sb->ent, compare_blame_final);
11431134
}
11441135

11451136
static int compare_commits_by_reverse_commit_date(const void *a,
@@ -1964,9 +1955,7 @@ static void pass_blame_to_parent(struct blame_scoreboard *sb,
19641955
parent, target, 0);
19651956
*d.dstq = NULL;
19661957
if (ignore_diffs)
1967-
newdest = llist_mergesort(newdest, get_next_blame,
1968-
set_next_blame,
1969-
compare_blame_suspect);
1958+
sort_blame_entries(&newdest, compare_blame_suspect);
19701959
queue_blames(sb, parent, newdest);
19711960

19721961
return;
@@ -2383,8 +2372,7 @@ static int num_scapegoats(struct rev_info *revs, struct commit *commit, int reve
23832372
*/
23842373
static void distribute_blame(struct blame_scoreboard *sb, struct blame_entry *blamed)
23852374
{
2386-
blamed = llist_mergesort(blamed, get_next_blame, set_next_blame,
2387-
compare_blame_suspect);
2375+
sort_blame_entries(&blamed, compare_blame_suspect);
23882376
while (blamed)
23892377
{
23902378
struct blame_origin *porigin = blamed->suspect;

commit.c

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -642,31 +642,23 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm
642642
return commit_list_insert(item, pp);
643643
}
644644

645-
static int commit_list_compare_by_date(const void *a, const void *b)
645+
static int commit_list_compare_by_date(const struct commit_list *a,
646+
const struct commit_list *b)
646647
{
647-
timestamp_t a_date = ((const struct commit_list *)a)->item->date;
648-
timestamp_t b_date = ((const struct commit_list *)b)->item->date;
648+
timestamp_t a_date = a->item->date;
649+
timestamp_t b_date = b->item->date;
649650
if (a_date < b_date)
650651
return 1;
651652
if (a_date > b_date)
652653
return -1;
653654
return 0;
654655
}
655656

656-
static void *commit_list_get_next(const void *a)
657-
{
658-
return ((const struct commit_list *)a)->next;
659-
}
660-
661-
static void commit_list_set_next(void *a, void *next)
662-
{
663-
((struct commit_list *)a)->next = next;
664-
}
657+
DEFINE_LIST_SORT(static, commit_list_sort, struct commit_list, next);
665658

666659
void commit_list_sort_by_date(struct commit_list **list)
667660
{
668-
*list = llist_mergesort(*list, commit_list_get_next, commit_list_set_next,
669-
commit_list_compare_by_date);
661+
commit_list_sort(list, commit_list_compare_by_date);
670662
}
671663

672664
struct commit *pop_most_recent_commit(struct commit_list **list,

fetch-pack.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "commit-reach.h"
2727
#include "commit-graph.h"
2828
#include "sigchain.h"
29+
#include "mergesort.h"
2930

3031
static int transfer_unpack_limit = -1;
3132
static int fetch_unpack_limit = -1;
@@ -1025,6 +1026,13 @@ static int get_pack(struct fetch_pack_args *args,
10251026
return 0;
10261027
}
10271028

1029+
static int ref_compare_name(const struct ref *a, const struct ref *b)
1030+
{
1031+
return strcmp(a->name, b->name);
1032+
}
1033+
1034+
DEFINE_LIST_SORT(static, sort_ref_list, struct ref, next);
1035+
10281036
static int cmp_ref_by_name(const void *a_, const void *b_)
10291037
{
10301038
const struct ref *a = *((const struct ref **)a_);

mergesort.c

Lines changed: 0 additions & 84 deletions
This file was deleted.

mergesort.h

Lines changed: 98 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,105 @@
11
#ifndef MERGESORT_H
22
#define MERGESORT_H
33

4+
/* Combine two sorted lists. Take from `list` on equality. */
5+
#define DEFINE_LIST_MERGE_INTERNAL(name, type) \
6+
static type *name##__merge(type *list, type *other, \
7+
int (*compare_fn)(const type *, const type *))\
8+
{ \
9+
type *result = list, *tail; \
10+
int prefer_list = compare_fn(list, other) <= 0; \
11+
\
12+
if (!prefer_list) { \
13+
result = other; \
14+
SWAP(list, other); \
15+
} \
16+
for (;;) { \
17+
do { \
18+
tail = list; \
19+
list = name##__get_next(list); \
20+
if (!list) { \
21+
name##__set_next(tail, other); \
22+
return result; \
23+
} \
24+
} while (compare_fn(list, other) < prefer_list); \
25+
name##__set_next(tail, other); \
26+
prefer_list ^= 1; \
27+
SWAP(list, other); \
28+
} \
29+
}
30+
431
/*
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.
32+
* Perform an iterative mergesort using an array of sublists.
33+
*
34+
* n is the number of items.
35+
* ranks[i] is undefined if n & 2^i == 0, and assumed empty.
36+
* ranks[i] contains a sublist of length 2^i otherwise.
37+
*
38+
* The number of bits in a void pointer limits the number of objects
39+
* that can be created, and thus the number of array elements necessary
40+
* to be able to sort any valid list.
41+
*
42+
* Adding an item to this array is like incrementing a binary number;
43+
* positional values for set bits correspond to sublist lengths.
1144
*/
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 *));
45+
#define DEFINE_LIST_SORT_INTERNAL(scope, name, type) \
46+
scope void name(type **listp, \
47+
int (*compare_fn)(const type *, const type *)) \
48+
{ \
49+
type *list = *listp; \
50+
type *ranks[bitsizeof(type *)]; \
51+
size_t n = 0; \
52+
\
53+
if (!list) \
54+
return; \
55+
\
56+
for (;;) { \
57+
int i; \
58+
size_t m; \
59+
type *next = name##__get_next(list); \
60+
if (next) \
61+
name##__set_next(list, NULL); \
62+
for (i = 0, m = n;; i++, m >>= 1) { \
63+
if (m & 1) { \
64+
list = name##__merge(ranks[i], list, \
65+
compare_fn); \
66+
} else if (next) { \
67+
break; \
68+
} else if (!m) { \
69+
*listp = list; \
70+
return; \
71+
} \
72+
} \
73+
n++; \
74+
ranks[i] = list; \
75+
list = next; \
76+
} \
77+
}
78+
79+
#define DECLARE_LIST_SORT(scope, name, type) \
80+
scope void name(type **listp, \
81+
int (*compare_fn)(const type *, const type *))
82+
83+
#define DEFINE_LIST_SORT_DEBUG(scope, name, type, next_member, \
84+
on_get_next, on_set_next) \
85+
\
86+
static inline type *name##__get_next(const type *elem) \
87+
{ \
88+
on_get_next; \
89+
return elem->next_member; \
90+
} \
91+
\
92+
static inline void name##__set_next(type *elem, type *next) \
93+
{ \
94+
on_set_next; \
95+
elem->next_member = next; \
96+
} \
97+
\
98+
DEFINE_LIST_MERGE_INTERNAL(name, type) \
99+
DEFINE_LIST_SORT_INTERNAL(scope, name, type) \
100+
DECLARE_LIST_SORT(scope, name, type)
101+
102+
#define DEFINE_LIST_SORT(scope, name, type, next_member) \
103+
DEFINE_LIST_SORT_DEBUG(scope, name, type, next_member, (void)0, (void)0)
16104

17105
#endif

packfile.c

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -941,20 +941,10 @@ unsigned long repo_approximate_object_count(struct repository *r)
941941
return r->objects->approximate_object_count;
942942
}
943943

944-
static void *get_next_packed_git(const void *p)
945-
{
946-
return ((const struct packed_git *)p)->next;
947-
}
948-
949-
static void set_next_packed_git(void *p, void *next)
950-
{
951-
((struct packed_git *)p)->next = next;
952-
}
944+
DEFINE_LIST_SORT(static, sort_packs, struct packed_git, next);
953945

954-
static int sort_pack(const void *a_, const void *b_)
946+
static int sort_pack(const struct packed_git *a, const struct packed_git *b)
955947
{
956-
const struct packed_git *a = a_;
957-
const struct packed_git *b = b_;
958948
int st;
959949

960950
/*
@@ -981,9 +971,7 @@ static int sort_pack(const void *a_, const void *b_)
981971

982972
static void rearrange_packed_git(struct repository *r)
983973
{
984-
r->objects->packed_git = llist_mergesort(
985-
r->objects->packed_git, get_next_packed_git,
986-
set_next_packed_git, sort_pack);
974+
sort_packs(&r->objects->packed_git, sort_pack);
987975
}
988976

989977
static void prepare_packed_git_mru(struct repository *r)

0 commit comments

Comments
 (0)