Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Commit ba8e632

Browse files
committed
Merge branch 'rs/commit-list-sort-in-batch'
Setting up a revision traversal with many starting points was inefficient as these were placed in a date-order priority queue one-by-one. By René Scharfe (3) and Junio C Hamano (1) * rs/commit-list-sort-in-batch: mergesort: rename it to llist_mergesort() revision: insert unsorted, then sort in prepare_revision_walk() commit: use mergesort() in commit_list_sort_by_date() add mergesort() for linked lists
2 parents 58bbace + 7365c95 commit ba8e632

File tree

8 files changed

+188
-7
lines changed

8 files changed

+188
-7
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@
181181
/test-index-version
182182
/test-line-buffer
183183
/test-match-trees
184+
/test-mergesort
184185
/test-mktemp
185186
/test-parse-options
186187
/test-path-utils

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ TEST_PROGRAMS_NEED_X += test-genrandom
481481
TEST_PROGRAMS_NEED_X += test-index-version
482482
TEST_PROGRAMS_NEED_X += test-line-buffer
483483
TEST_PROGRAMS_NEED_X += test-match-trees
484+
TEST_PROGRAMS_NEED_X += test-mergesort
484485
TEST_PROGRAMS_NEED_X += test-mktemp
485486
TEST_PROGRAMS_NEED_X += test-parse-options
486487
TEST_PROGRAMS_NEED_X += test-path-utils
@@ -591,6 +592,7 @@ LIB_H += log-tree.h
591592
LIB_H += mailmap.h
592593
LIB_H += merge-file.h
593594
LIB_H += merge-recursive.h
595+
LIB_H += mergesort.h
594596
LIB_H += notes.h
595597
LIB_H += notes-cache.h
596598
LIB_H += notes-merge.h
@@ -695,6 +697,7 @@ LIB_OBJS += mailmap.o
695697
LIB_OBJS += match-trees.o
696698
LIB_OBJS += merge-file.o
697699
LIB_OBJS += merge-recursive.o
700+
LIB_OBJS += mergesort.o
698701
LIB_OBJS += name-hash.o
699702
LIB_OBJS += notes.o
700703
LIB_OBJS += notes-cache.o

commit.c

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "revision.h"
88
#include "notes.h"
99
#include "gpg-interface.h"
10+
#include "mergesort.h"
1011

1112
int save_commit_buffer = 1;
1213

@@ -360,6 +361,21 @@ struct commit_list *commit_list_insert(struct commit *item, struct commit_list *
360361
return new_list;
361362
}
362363

364+
void commit_list_reverse(struct commit_list **list_p)
365+
{
366+
struct commit_list *prev = NULL, *curr = *list_p, *next;
367+
368+
if (!list_p)
369+
return;
370+
while (curr) {
371+
next = curr->next;
372+
curr->next = prev;
373+
prev = curr;
374+
curr = next;
375+
}
376+
*list_p = prev;
377+
}
378+
363379
unsigned commit_list_count(const struct commit_list *l)
364380
{
365381
unsigned c = 0;
@@ -390,15 +406,31 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm
390406
return commit_list_insert(item, pp);
391407
}
392408

409+
static int commit_list_compare_by_date(const void *a, const void *b)
410+
{
411+
unsigned long a_date = ((const struct commit_list *)a)->item->date;
412+
unsigned long b_date = ((const struct commit_list *)b)->item->date;
413+
if (a_date < b_date)
414+
return 1;
415+
if (a_date > b_date)
416+
return -1;
417+
return 0;
418+
}
419+
420+
static void *commit_list_get_next(const void *a)
421+
{
422+
return ((const struct commit_list *)a)->next;
423+
}
424+
425+
static void commit_list_set_next(void *a, void *next)
426+
{
427+
((struct commit_list *)a)->next = next;
428+
}
393429

394430
void commit_list_sort_by_date(struct commit_list **list)
395431
{
396-
struct commit_list *ret = NULL;
397-
while (*list) {
398-
commit_list_insert_by_date((*list)->item, &ret);
399-
*list = (*list)->next;
400-
}
401-
*list = ret;
432+
*list = llist_mergesort(*list, commit_list_get_next, commit_list_set_next,
433+
commit_list_compare_by_date);
402434
}
403435

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

commit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ unsigned commit_list_count(const struct commit_list *l);
5757
struct commit_list *commit_list_insert_by_date(struct commit *item,
5858
struct commit_list **list);
5959
void commit_list_sort_by_date(struct commit_list **list);
60+
void commit_list_reverse(struct commit_list **list_p);
6061

6162
void free_commit_list(struct commit_list *list);
6263

mergesort.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#include "cache.h"
2+
#include "mergesort.h"
3+
4+
struct mergesort_sublist {
5+
void *ptr;
6+
unsigned long len;
7+
};
8+
9+
static void *get_nth_next(void *list, unsigned long n,
10+
void *(*get_next_fn)(const void *))
11+
{
12+
while (n-- && list)
13+
list = get_next_fn(list);
14+
return list;
15+
}
16+
17+
static void *pop_item(struct mergesort_sublist *l,
18+
void *(*get_next_fn)(const void *))
19+
{
20+
void *p = l->ptr;
21+
l->ptr = get_next_fn(l->ptr);
22+
l->len = l->ptr ? (l->len - 1) : 0;
23+
return p;
24+
}
25+
26+
void *llist_mergesort(void *list,
27+
void *(*get_next_fn)(const void *),
28+
void (*set_next_fn)(void *, void *),
29+
int (*compare_fn)(const void *, const void *))
30+
{
31+
unsigned long l;
32+
33+
if (!list)
34+
return NULL;
35+
for (l = 1; ; l *= 2) {
36+
void *curr;
37+
struct mergesort_sublist p, q;
38+
39+
p.ptr = list;
40+
q.ptr = get_nth_next(p.ptr, l, get_next_fn);
41+
if (!q.ptr)
42+
break;
43+
p.len = q.len = l;
44+
45+
if (compare_fn(p.ptr, q.ptr) > 0)
46+
list = curr = pop_item(&q, get_next_fn);
47+
else
48+
list = curr = pop_item(&p, get_next_fn);
49+
50+
while (p.ptr) {
51+
while (p.len || q.len) {
52+
void *prev = curr;
53+
54+
if (!p.len)
55+
curr = pop_item(&q, get_next_fn);
56+
else if (!q.len)
57+
curr = pop_item(&p, get_next_fn);
58+
else if (compare_fn(p.ptr, q.ptr) > 0)
59+
curr = pop_item(&q, get_next_fn);
60+
else
61+
curr = pop_item(&p, get_next_fn);
62+
set_next_fn(prev, curr);
63+
}
64+
p.ptr = q.ptr;
65+
p.len = l;
66+
q.ptr = get_nth_next(p.ptr, l, get_next_fn);
67+
q.len = q.ptr ? l : 0;
68+
69+
}
70+
set_next_fn(curr, NULL);
71+
}
72+
return list;
73+
}

mergesort.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef MERGESORT_H
2+
#define MERGESORT_H
3+
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 *));
16+
17+
#endif

revision.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2076,11 +2076,13 @@ int prepare_revision_walk(struct rev_info *revs)
20762076
if (commit) {
20772077
if (!(commit->object.flags & SEEN)) {
20782078
commit->object.flags |= SEEN;
2079-
commit_list_insert_by_date(commit, &revs->commits);
2079+
commit_list_insert(commit, &revs->commits);
20802080
}
20812081
}
20822082
e++;
20832083
}
2084+
commit_list_reverse(&revs->commits);
2085+
commit_list_sort_by_date(&revs->commits);
20842086
if (!revs->leak_pending)
20852087
free(list);
20862088

test-mergesort.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#include "cache.h"
2+
#include "mergesort.h"
3+
4+
struct line {
5+
char *text;
6+
struct line *next;
7+
};
8+
9+
static void *get_next(const void *a)
10+
{
11+
return ((const struct line *)a)->next;
12+
}
13+
14+
static void set_next(void *a, void *b)
15+
{
16+
((struct line *)a)->next = b;
17+
}
18+
19+
static int compare_strings(const void *a, const void *b)
20+
{
21+
const struct line *x = a, *y = b;
22+
return strcmp(x->text, y->text);
23+
}
24+
25+
int main(int argc, const char **argv)
26+
{
27+
struct line *line, *p = NULL, *lines = NULL;
28+
struct strbuf sb = STRBUF_INIT;
29+
30+
for (;;) {
31+
if (strbuf_getwholeline(&sb, stdin, '\n'))
32+
break;
33+
line = xmalloc(sizeof(struct line));
34+
line->text = strbuf_detach(&sb, NULL);
35+
if (p) {
36+
line->next = p->next;
37+
p->next = line;
38+
} else {
39+
line->next = NULL;
40+
lines = line;
41+
}
42+
p = line;
43+
}
44+
45+
lines = llist_mergesort(lines, get_next, set_next, compare_strings);
46+
47+
while (lines) {
48+
printf("%s", lines->text);
49+
lines = lines->next;
50+
}
51+
return 0;
52+
}

0 commit comments

Comments
 (0)