99#include "gpg-interface.h"
1010#include "mergesort.h"
1111#include "commit-slab.h"
12+ #include "prio-queue.h"
1213
1314static struct commit_extra_header * read_commit_extra_header_lines (const char * buf , size_t len , const char * * );
1415
@@ -518,31 +519,124 @@ struct commit *pop_commit(struct commit_list **stack)
518519/* count number of children that have not been emitted */
519520define_commit_slab (indegree_slab , int );
520521
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+
521595/*
522596 * Performs an in-place topological sort on the list supplied.
523597 */
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 )
525599{
526600 struct commit_list * next , * orig = * list ;
527- struct commit_list * work , * * insert ;
528601 struct commit_list * * pptr ;
529602 struct indegree_slab indegree ;
603+ struct prio_queue queue ;
604+ struct commit * commit ;
605+ struct author_date_slab author_date ;
530606
531607 if (!orig )
532608 return ;
533609 * list = NULL ;
534610
535611 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+ }
536627
537628 /* Mark them and clear the indegree */
538629 for (next = orig ; next ; next = next -> next ) {
539630 struct commit * commit = next -> item ;
540631 * (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 );
541635 }
542636
543637 /* update the indegree */
544638 for (next = orig ; next ; next = next -> next ) {
545- struct commit_list * parents = next -> item -> parents ;
639+ struct commit_list * parents = next -> item -> parents ;
546640 while (parents ) {
547641 struct commit * parent = parents -> item ;
548642 int * pi = indegree_slab_at (& indegree , parent );
@@ -560,30 +654,28 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
560654 *
561655 * the tips serve as a starting set for the work queue.
562656 */
563- work = NULL ;
564- insert = & work ;
565657 for (next = orig ; next ; next = next -> next ) {
566658 struct commit * commit = next -> item ;
567659
568660 if (* (indegree_slab_at (& indegree , commit )) == 1 )
569- insert = & commit_list_insert ( commit , insert ) -> next ;
661+ prio_queue_put ( & queue , commit ) ;
570662 }
571663
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 );
575673
576674 pptr = list ;
577675 * 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 ;
585678
586- commit = work_item -> item ;
587679 for (parents = commit -> parents ; parents ; parents = parents -> next ) {
588680 struct commit * parent = parents -> item ;
589681 int * pi = indegree_slab_at (& indegree , parent );
@@ -596,23 +688,22 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
596688 * when all their children have been emitted thereby
597689 * guaranteeing topological order.
598690 */
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 );
605693 }
606694 /*
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.
609697 */
610698 * (indegree_slab_at (& indegree , commit )) = 0 ;
611- * pptr = work_item ;
612- pptr = & work_item -> next ;
699+
700+ pptr = & commit_list_insert ( commit , pptr ) -> next ;
613701 }
614702
615703 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 );
616707}
617708
618709/* merge-base stuff */
0 commit comments