9
9
#include "gpg-interface.h"
10
10
#include "mergesort.h"
11
11
#include "commit-slab.h"
12
+ #include "prio-queue.h"
12
13
13
14
static struct commit_extra_header * read_commit_extra_header_lines (const char * buf , size_t len , const char * * );
14
15
@@ -518,31 +519,124 @@ struct commit *pop_commit(struct commit_list **stack)
518
519
/* count number of children that have not been emitted */
519
520
define_commit_slab (indegree_slab , int );
520
521
522
+ /* record author-date for each commit object */
523
+ define_commit_slab (author_date_slab , unsigned long );
524
+
525
+ static void record_author_date (struct author_date_slab * author_date ,
526
+ struct commit * commit )
527
+ {
528
+ const char * buf , * line_end ;
529
+ char * buffer = NULL ;
530
+ struct ident_split ident ;
531
+ char * date_end ;
532
+ unsigned long date ;
533
+
534
+ if (!commit -> buffer ) {
535
+ unsigned long size ;
536
+ enum object_type type ;
537
+ buffer = read_sha1_file (commit -> object .sha1 , & type , & size );
538
+ if (!buffer )
539
+ return ;
540
+ }
541
+
542
+ for (buf = commit -> buffer ? commit -> buffer : buffer ;
543
+ buf ;
544
+ buf = line_end + 1 ) {
545
+ line_end = strchrnul (buf , '\n' );
546
+ if (prefixcmp (buf , "author " )) {
547
+ if (!line_end [0 ] || line_end [1 ] == '\n' )
548
+ return ; /* end of header */
549
+ continue ;
550
+ }
551
+ if (split_ident_line (& ident ,
552
+ buf + strlen ("author " ),
553
+ line_end - (buf + strlen ("author " ))) ||
554
+ !ident .date_begin || !ident .date_end )
555
+ goto fail_exit ; /* malformed "author" line */
556
+ break ;
557
+ }
558
+
559
+ date = strtoul (ident .date_begin , & date_end , 10 );
560
+ if (date_end != ident .date_end )
561
+ goto fail_exit ; /* malformed date */
562
+ * (author_date_slab_at (author_date , commit )) = date ;
563
+
564
+ fail_exit :
565
+ free (buffer );
566
+ }
567
+
568
+ static int compare_commits_by_author_date (const void * a_ , const void * b_ ,
569
+ void * cb_data )
570
+ {
571
+ const struct commit * a = a_ , * b = b_ ;
572
+ struct author_date_slab * author_date = cb_data ;
573
+ unsigned long a_date = * (author_date_slab_at (author_date , a ));
574
+ unsigned long b_date = * (author_date_slab_at (author_date , b ));
575
+
576
+ /* newer commits with larger date first */
577
+ if (a_date < b_date )
578
+ return 1 ;
579
+ else if (a_date > b_date )
580
+ return -1 ;
581
+ return 0 ;
582
+ }
583
+
584
+ static int compare_commits_by_commit_date (const void * a_ , const void * b_ , void * unused )
585
+ {
586
+ const struct commit * a = a_ , * b = b_ ;
587
+ /* newer commits with larger date first */
588
+ if (a -> date < b -> date )
589
+ return 1 ;
590
+ else if (a -> date > b -> date )
591
+ return -1 ;
592
+ return 0 ;
593
+ }
594
+
521
595
/*
522
596
* Performs an in-place topological sort on the list supplied.
523
597
*/
524
- void sort_in_topological_order (struct commit_list * * list , int lifo )
598
+ void sort_in_topological_order (struct commit_list * * list , enum rev_sort_order sort_order )
525
599
{
526
600
struct commit_list * next , * orig = * list ;
527
- struct commit_list * work , * * insert ;
528
601
struct commit_list * * pptr ;
529
602
struct indegree_slab indegree ;
603
+ struct prio_queue queue ;
604
+ struct commit * commit ;
605
+ struct author_date_slab author_date ;
530
606
531
607
if (!orig )
532
608
return ;
533
609
* list = NULL ;
534
610
535
611
init_indegree_slab (& indegree );
612
+ memset (& queue , '\0' , sizeof (queue ));
613
+
614
+ switch (sort_order ) {
615
+ default : /* REV_SORT_IN_GRAPH_ORDER */
616
+ queue .compare = NULL ;
617
+ break ;
618
+ case REV_SORT_BY_COMMIT_DATE :
619
+ queue .compare = compare_commits_by_commit_date ;
620
+ break ;
621
+ case REV_SORT_BY_AUTHOR_DATE :
622
+ init_author_date_slab (& author_date );
623
+ queue .compare = compare_commits_by_author_date ;
624
+ queue .cb_data = & author_date ;
625
+ break ;
626
+ }
536
627
537
628
/* Mark them and clear the indegree */
538
629
for (next = orig ; next ; next = next -> next ) {
539
630
struct commit * commit = next -> item ;
540
631
* (indegree_slab_at (& indegree , commit )) = 1 ;
632
+ /* also record the author dates, if needed */
633
+ if (sort_order == REV_SORT_BY_AUTHOR_DATE )
634
+ record_author_date (& author_date , commit );
541
635
}
542
636
543
637
/* update the indegree */
544
638
for (next = orig ; next ; next = next -> next ) {
545
- struct commit_list * parents = next -> item -> parents ;
639
+ struct commit_list * parents = next -> item -> parents ;
546
640
while (parents ) {
547
641
struct commit * parent = parents -> item ;
548
642
int * pi = indegree_slab_at (& indegree , parent );
@@ -560,30 +654,28 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
560
654
*
561
655
* the tips serve as a starting set for the work queue.
562
656
*/
563
- work = NULL ;
564
- insert = & work ;
565
657
for (next = orig ; next ; next = next -> next ) {
566
658
struct commit * commit = next -> item ;
567
659
568
660
if (* (indegree_slab_at (& indegree , commit )) == 1 )
569
- insert = & commit_list_insert ( commit , insert ) -> next ;
661
+ prio_queue_put ( & queue , commit ) ;
570
662
}
571
663
572
- /* process the list in topological order */
573
- if (!lifo )
574
- commit_list_sort_by_date (& work );
664
+ /*
665
+ * This is unfortunate; the initial tips need to be shown
666
+ * in the order given from the revision traversal machinery.
667
+ */
668
+ if (sort_order == REV_SORT_IN_GRAPH_ORDER )
669
+ prio_queue_reverse (& queue );
670
+
671
+ /* We no longer need the commit list */
672
+ free_commit_list (orig );
575
673
576
674
pptr = list ;
577
675
* list = NULL ;
578
- while (work ) {
579
- struct commit * commit ;
580
- struct commit_list * parents , * work_item ;
581
-
582
- work_item = work ;
583
- work = work_item -> next ;
584
- work_item -> next = NULL ;
676
+ while ((commit = prio_queue_get (& queue )) != NULL ) {
677
+ struct commit_list * parents ;
585
678
586
- commit = work_item -> item ;
587
679
for (parents = commit -> parents ; parents ; parents = parents -> next ) {
588
680
struct commit * parent = parents -> item ;
589
681
int * pi = indegree_slab_at (& indegree , parent );
@@ -596,23 +688,22 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
596
688
* when all their children have been emitted thereby
597
689
* guaranteeing topological order.
598
690
*/
599
- if (-- (* pi ) == 1 ) {
600
- if (!lifo )
601
- commit_list_insert_by_date (parent , & work );
602
- else
603
- commit_list_insert (parent , & work );
604
- }
691
+ if (-- (* pi ) == 1 )
692
+ prio_queue_put (& queue , parent );
605
693
}
606
694
/*
607
- * work_item is a commit all of whose children
608
- * have already been emitted. we can emit it now.
695
+ * all children of commit have already been
696
+ * emitted. we can emit it now.
609
697
*/
610
698
* (indegree_slab_at (& indegree , commit )) = 0 ;
611
- * pptr = work_item ;
612
- pptr = & work_item -> next ;
699
+
700
+ pptr = & commit_list_insert ( commit , pptr ) -> next ;
613
701
}
614
702
615
703
clear_indegree_slab (& indegree );
704
+ clear_prio_queue (& queue );
705
+ if (sort_order == REV_SORT_BY_AUTHOR_DATE )
706
+ clear_author_date_slab (& author_date );
616
707
}
617
708
618
709
/* merge-base stuff */
0 commit comments