1616
1717use std:: cmp:: max;
1818use std:: cmp:: Ordering ;
19+ use std:: cmp:: Reverse ;
1920use std:: collections:: binary_heap;
20- use std:: collections:: BTreeSet ;
2121use std:: collections:: BinaryHeap ;
2222use std:: collections:: HashSet ;
2323use std:: iter;
@@ -312,20 +312,23 @@ impl CompositeIndex {
312312 false
313313 }
314314
315+ /// Computes the greatest common ancestors.
316+ ///
317+ /// The returned index positions are sorted in descending order.
315318 pub ( super ) fn common_ancestors_pos (
316319 & self ,
317320 set1 : & [ IndexPosition ] ,
318321 set2 : & [ IndexPosition ] ,
319- ) -> BTreeSet < IndexPosition > {
322+ ) -> Vec < IndexPosition > {
320323 let mut items1: BinaryHeap < _ > = set1. iter ( ) . copied ( ) . collect ( ) ;
321324 let mut items2: BinaryHeap < _ > = set2. iter ( ) . copied ( ) . collect ( ) ;
322- let mut result = BTreeSet :: new ( ) ;
325+ let mut result = Vec :: new ( ) ;
323326 while let ( Some ( & pos1) , Some ( & pos2) ) = ( items1. peek ( ) , items2. peek ( ) ) {
324327 match pos1. cmp ( & pos2) {
325328 Ordering :: Greater => shift_to_parents ( & mut items1, & self . entry_by_pos ( pos1) ) ,
326329 Ordering :: Less => shift_to_parents ( & mut items2, & self . entry_by_pos ( pos2) ) ,
327330 Ordering :: Equal => {
328- result. insert ( pos1) ;
331+ result. push ( pos1) ;
329332 dedup_pop ( & mut items1) . unwrap ( ) ;
330333 dedup_pop ( & mut items2) . unwrap ( ) ;
331334 }
@@ -358,24 +361,29 @@ impl CompositeIndex {
358361
359362 /// Returns the subset of positions in `candidate_positions` which refer to
360363 /// entries that are heads in the repository.
361- pub fn heads_pos(
362- & self ,
363- candidate_positions : BTreeSet < IndexPosition > ,
364- ) -> BTreeSet < IndexPosition > {
364+ ///
365+ /// The `candidate_positions` must be sorted in descending order, and have
366+ /// no duplicates. The returned head positions are also sorted in descending
367+ /// order.
368+ pub fn heads_pos( & self , candidate_positions : Vec < IndexPosition > ) -> Vec < IndexPosition > {
369+ debug_assert ! ( candidate_positions
370+ . iter( )
371+ . tuple_windows( )
372+ . all( |( a, b) | a > b) ) ;
365373 let Some ( min_generation) = candidate_positions
366374 . iter ( )
367375 . map ( |& pos| self . entry_by_pos ( pos) . generation_number ( ) )
368376 . min ( )
369377 else {
370- return BTreeSet :: new ( ) ;
378+ return candidate_positions ;
371379 } ;
372380
373381 // Iterate though the candidates by reverse index position, keeping track of the
374382 // ancestors of already-found heads. If a candidate is an ancestor of an
375383 // already-found head, then it can be removed.
376384 let mut parents = BinaryHeap :: new ( ) ;
377- let mut heads = BTreeSet :: new ( ) ;
378- ' outer: for candidate in candidate_positions. into_iter ( ) . rev ( ) {
385+ let mut heads = Vec :: new ( ) ;
386+ ' outer: for candidate in candidate_positions {
379387 while let Some ( & parent) = parents. peek ( ) . filter ( |& & parent| parent >= candidate) {
380388 let entry = self . entry_by_pos ( parent) ;
381389 if entry. generation_number ( ) <= min_generation {
@@ -391,7 +399,7 @@ impl CompositeIndex {
391399 // No parents matched, so this commit is a head.
392400 let entry = self . entry_by_pos ( candidate) ;
393401 parents. extend ( entry. parent_positions ( ) ) ;
394- heads. insert ( candidate) ;
402+ heads. push ( candidate) ;
395403 }
396404 heads
397405 }
@@ -475,9 +483,11 @@ impl Index for &CompositeIndex {
475483 & self ,
476484 candidate_ids : & mut dyn Iterator < Item = & CommitId > ,
477485 ) -> Result < Vec < CommitId > , IndexError > {
478- let candidate_positions : BTreeSet < _ > = candidate_ids
486+ let mut candidate_positions = candidate_ids
479487 . map ( |id| self . commit_id_to_pos ( id) . unwrap ( ) )
480- . collect ( ) ;
488+ . collect_vec ( ) ;
489+ candidate_positions. sort_unstable_by_key ( |& pos| Reverse ( pos) ) ;
490+ candidate_positions. dedup ( ) ;
481491
482492 Ok ( self
483493 . heads_pos ( candidate_positions)
0 commit comments