@@ -357,39 +357,16 @@ static int revwalk_next_unsorted(git_commit_list_node **object_out, git_revwalk
357357
358358static int revwalk_next_toposort (git_commit_list_node * * object_out , git_revwalk * walk )
359359{
360- git_commit_list_node * next ;
361- unsigned short i , max ;
362-
363- for (;;) {
364- next = git_commit_list_pop (& walk -> iterator_topo );
365- if (next == NULL ) {
366- giterr_clear ();
367- return GIT_ITEROVER ;
368- }
369-
370- if (next -> in_degree > 0 ) {
371- next -> topo_delay = 1 ;
372- continue ;
373- }
374-
375-
376- max = next -> out_degree ;
377- if (walk -> first_parent && next -> out_degree )
378- max = 1 ;
360+ git_commit_list_node * node ;
379361
380- for (i = 0 ; i < max ; ++ i ) {
381- git_commit_list_node * parent = next -> parents [i ];
382-
383- if (-- parent -> in_degree == 0 && parent -> topo_delay ) {
384- parent -> topo_delay = 0 ;
385- if (git_commit_list_insert (parent , & walk -> iterator_topo ) == NULL )
386- return -1 ;
387- }
388- }
389-
390- * object_out = next ;
362+ node = git_commit_list_pop (& walk -> iterator_topo );
363+ if (node ) {
364+ * object_out = node ;
391365 return 0 ;
392366 }
367+
368+ giterr_clear ();
369+ return GIT_ITEROVER ;
393370}
394371
395372static int revwalk_next_reverse (git_commit_list_node * * object_out , git_revwalk * walk )
@@ -453,8 +430,6 @@ static int add_parents_to_list(git_revwalk *walk, git_commit_list_node *commit,
453430
454431 commit -> added = 1 ;
455432
456- /* TODO: add the insertion callback here as well */
457-
458433 /*
459434 * Go full on in the uninteresting case as we want to include
460435 * as many of these as we can.
@@ -494,7 +469,7 @@ static int add_parents_to_list(git_revwalk *walk, git_commit_list_node *commit,
494469 return error ;
495470
496471 if (walk -> hide_cb && walk -> hide_cb (& p -> oid , walk -> hide_cb_payload ))
497- continue ;
472+ continue ;
498473
499474 if (!p -> seen ) {
500475 p -> seen = 1 ;
@@ -578,10 +553,104 @@ static int limit_list(git_commit_list **out, git_revwalk *walk, git_commit_list
578553 p = & git_commit_list_insert (commit , p )-> next ;
579554 }
580555
556+ git_commit_list_free (& list );
581557 * out = newlist ;
582558 return 0 ;
583559}
584560
561+ static int sort_in_topological_order (git_commit_list * * out , git_revwalk * walk )
562+ {
563+ git_commit_list * list = NULL , * ll = NULL , * newlist , * * pptr ;
564+ git_commit_list_node * next ;
565+ git_pqueue queue ;
566+ git_vector_cmp queue_cmp = NULL ;
567+ unsigned short i ;
568+ int error ;
569+
570+ if (walk -> sorting & GIT_SORT_TIME )
571+ queue_cmp = git_commit_list_time_cmp ;
572+
573+ if ((error = git_pqueue_init (& queue , 0 , 8 , queue_cmp )))
574+ return error ;
575+
576+ /*
577+ * Start by resetting the in-degree to 1 for the commits in
578+ * our list. We want to go through this list again, so we
579+ * store it in the commit list as we extract it from the lower
580+ * machinery.
581+ */
582+ while ((error = walk -> get_next (& next , walk )) == 0 ) {
583+ next -> in_degree = 1 ;
584+ git_commit_list_insert (next , & list );
585+ }
586+
587+ if (error != GIT_ITEROVER )
588+ goto cleanup ;
589+
590+ error = 0 ;
591+
592+ /*
593+ * Count up how many children each commit has. We limit
594+ * ourselves to those commits in the original list (in-degree
595+ * of 1) avoiding setting it for any parent that was hidden.
596+ */
597+ for (ll = list ; ll ; ll = ll -> next ) {
598+ for (i = 0 ; i < ll -> item -> out_degree ; ++ i ) {
599+ git_commit_list_node * parent = ll -> item -> parents [i ];
600+ if (parent -> in_degree )
601+ parent -> in_degree ++ ;
602+ }
603+ }
604+
605+ /*
606+ * Now we find the tips i.e. those not reachable from any other node
607+ * i.e. those which still have an in-degree of 1.
608+ */
609+ for (ll = list ; ll ; ll = ll -> next ) {
610+ if (ll -> item -> in_degree == 1 ) {
611+ if ((error = git_pqueue_insert (& queue , ll -> item )))
612+ goto cleanup ;
613+ }
614+ }
615+
616+ /*
617+ * We need to output the tips in the order that they came out of the
618+ * traversal, so if we're not doing time-sorting, we need to reverse the
619+ * pqueue in order to get them to come out as we inserted them.
620+ */
621+ if ((walk -> sorting & GIT_SORT_TIME ) == 0 )
622+ git_pqueue_reverse (& queue );
623+
624+
625+ pptr = & newlist ;
626+ newlist = NULL ;
627+ while ((next = git_pqueue_pop (& queue )) != NULL ) {
628+ for (i = 0 ; i < next -> out_degree ; ++ i ) {
629+ git_commit_list_node * parent = next -> parents [i ];
630+ if (parent -> in_degree == 0 )
631+ continue ;
632+
633+ if (-- parent -> in_degree == 1 ) {
634+ if ((error = git_pqueue_insert (& queue , parent )))
635+ goto cleanup ;
636+ }
637+ }
638+
639+ /* All the children of 'item' have been emitted (since we got to it via the priority queue) */
640+ next -> in_degree = 0 ;
641+
642+ pptr = & git_commit_list_insert (next , pptr )-> next ;
643+ }
644+
645+ * out = newlist ;
646+ error = 0 ;
647+
648+ cleanup :
649+ git_commit_list_free (& list );
650+ git_pqueue_free (& queue );
651+ return error ;
652+ }
653+
585654static int prepare_walk (git_revwalk * walk )
586655{
587656 int error ;
@@ -615,25 +684,16 @@ static int prepare_walk(git_revwalk *walk)
615684 if (list -> item -> uninteresting )
616685 continue ;
617686
618- if ((error = walk -> enqueue (walk , list -> item )) < 0 )
687+ if ((error = walk -> enqueue (walk , list -> item )) < 0 ) {
688+ git_commit_list_free (& commits );
619689 return error ;
690+ }
620691 }
621692
693+ git_commit_list_free (& commits );
622694
623695 if (walk -> sorting & GIT_SORT_TOPOLOGICAL ) {
624- unsigned short i ;
625-
626- while ((error = walk -> get_next (& next , walk )) == 0 ) {
627- for (i = 0 ; i < next -> out_degree ; ++ i ) {
628- git_commit_list_node * parent = next -> parents [i ];
629- parent -> in_degree ++ ;
630- }
631-
632- if (git_commit_list_insert (next , & walk -> iterator_topo ) == NULL )
633- return -1 ;
634- }
635-
636- if (error != GIT_ITEROVER )
696+ if ((error = sort_in_topological_order (& walk -> iterator_topo , walk )))
637697 return error ;
638698
639699 walk -> get_next = & revwalk_next_toposort ;
0 commit comments