Skip to content

Commit da24b10

Browse files
committed
sort-in-topological-order: use prio-queue
Use the prio-queue data structure to implement a priority queue of commits sorted by committer date, when handling --date-order. The structure can also be used as a simple LIFO stack, which is a good match for --topo-order processing. Signed-off-by: Junio C Hamano <[email protected]>
1 parent b4b594a commit da24b10

File tree

3 files changed

+60
-31
lines changed

3 files changed

+60
-31
lines changed

commit.c

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "gpg-interface.h"
1010
#include "mergesort.h"
1111
#include "commit-slab.h"
12+
#include "prio-queue.h"
1213

1314
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
1415

@@ -509,21 +510,42 @@ struct commit *pop_commit(struct commit_list **stack)
509510
/* count number of children that have not been emitted */
510511
define_commit_slab(indegree_slab, int);
511512

513+
static int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused)
514+
{
515+
const struct commit *a = a_, *b = b_;
516+
/* newer commits with larger date first */
517+
if (a->date < b->date)
518+
return 1;
519+
else if (a->date > b->date)
520+
return -1;
521+
return 0;
522+
}
523+
512524
/*
513525
* Performs an in-place topological sort on the list supplied.
514526
*/
515-
void sort_in_topological_order(struct commit_list ** list, enum rev_sort_order sort_order)
527+
void sort_in_topological_order(struct commit_list **list, enum rev_sort_order sort_order)
516528
{
517529
struct commit_list *next, *orig = *list;
518-
struct commit_list *work, **insert;
519530
struct commit_list **pptr;
520531
struct indegree_slab indegree;
532+
struct prio_queue queue;
533+
struct commit *commit;
521534

522535
if (!orig)
523536
return;
524537
*list = NULL;
525538

526539
init_indegree_slab(&indegree);
540+
memset(&queue, '\0', sizeof(queue));
541+
switch (sort_order) {
542+
default: /* REV_SORT_IN_GRAPH_ORDER */
543+
queue.compare = NULL;
544+
break;
545+
case REV_SORT_BY_COMMIT_DATE:
546+
queue.compare = compare_commits_by_commit_date;
547+
break;
548+
}
527549

528550
/* Mark them and clear the indegree */
529551
for (next = orig; next; next = next->next) {
@@ -533,7 +555,7 @@ void sort_in_topological_order(struct commit_list ** list, enum rev_sort_order s
533555

534556
/* update the indegree */
535557
for (next = orig; next; next = next->next) {
536-
struct commit_list * parents = next->item->parents;
558+
struct commit_list *parents = next->item->parents;
537559
while (parents) {
538560
struct commit *parent = parents->item;
539561
int *pi = indegree_slab_at(&indegree, parent);
@@ -551,30 +573,28 @@ void sort_in_topological_order(struct commit_list ** list, enum rev_sort_order s
551573
*
552574
* the tips serve as a starting set for the work queue.
553575
*/
554-
work = NULL;
555-
insert = &work;
556576
for (next = orig; next; next = next->next) {
557577
struct commit *commit = next->item;
558578

559579
if (*(indegree_slab_at(&indegree, commit)) == 1)
560-
insert = &commit_list_insert(commit, insert)->next;
580+
prio_queue_put(&queue, commit);
561581
}
562582

563-
/* process the list in topological order */
564-
if (sort_order != REV_SORT_IN_GRAPH_ORDER)
565-
commit_list_sort_by_date(&work);
583+
/*
584+
* This is unfortunate; the initial tips need to be shown
585+
* in the order given from the revision traversal machinery.
586+
*/
587+
if (sort_order == REV_SORT_IN_GRAPH_ORDER)
588+
prio_queue_reverse(&queue);
589+
590+
/* We no longer need the commit list */
591+
free_commit_list(orig);
566592

567593
pptr = list;
568594
*list = NULL;
569-
while (work) {
570-
struct commit *commit;
571-
struct commit_list *parents, *work_item;
572-
573-
work_item = work;
574-
work = work_item->next;
575-
work_item->next = NULL;
595+
while ((commit = prio_queue_get(&queue)) != NULL) {
596+
struct commit_list *parents;
576597

577-
commit = work_item->item;
578598
for (parents = commit->parents; parents ; parents = parents->next) {
579599
struct commit *parent = parents->item;
580600
int *pi = indegree_slab_at(&indegree, parent);
@@ -587,27 +607,20 @@ void sort_in_topological_order(struct commit_list ** list, enum rev_sort_order s
587607
* when all their children have been emitted thereby
588608
* guaranteeing topological order.
589609
*/
590-
if (--(*pi) == 1) {
591-
switch (sort_order) {
592-
case REV_SORT_BY_COMMIT_DATE:
593-
commit_list_insert_by_date(parent, &work);
594-
break;
595-
default: /* REV_SORT_IN_GRAPH_ORDER */
596-
commit_list_insert(parent, &work);
597-
break;
598-
}
599-
}
610+
if (--(*pi) == 1)
611+
prio_queue_put(&queue, parent);
600612
}
601613
/*
602-
* work_item is a commit all of whose children
603-
* have already been emitted. we can emit it now.
614+
* all children of commit have already been
615+
* emitted. we can emit it now.
604616
*/
605617
*(indegree_slab_at(&indegree, commit)) = 0;
606-
*pptr = work_item;
607-
pptr = &work_item->next;
618+
619+
pptr = &commit_list_insert(commit, pptr)->next;
608620
}
609621

610622
clear_indegree_slab(&indegree);
623+
clear_prio_queue(&queue);
611624
}
612625

613626
/* merge-base stuff */

prio-queue.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22
#include "commit.h"
33
#include "prio-queue.h"
44

5+
void prio_queue_reverse(struct prio_queue *queue)
6+
{
7+
int i, j;
8+
9+
if (queue->compare != NULL)
10+
die("BUG: prio_queue_reverse() on non-LIFO queue");
11+
for (i = 0; i <= (j = (queue->nr - 1) - i); i++) {
12+
struct commit *swap = queue->array[i];
13+
queue->array[i] = queue->array[j];
14+
queue->array[j] = swap;
15+
}
16+
}
17+
518
void clear_prio_queue(struct prio_queue *queue)
619
{
720
free(queue->array);

prio-queue.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,7 @@ extern void *prio_queue_get(struct prio_queue *);
4242

4343
extern void clear_prio_queue(struct prio_queue *);
4444

45+
/* Reverse the LIFO elements */
46+
extern void prio_queue_reverse(struct prio_queue *);
47+
4548
#endif /* PRIO_QUEUE_H */

0 commit comments

Comments
 (0)