Skip to content

Commit f9c34a6

Browse files
committed
index: make common_ancestors_pos() and heads_pos() return sorted Vec
Thanks to 56b3939, we no longer do random deletion, and most callers keep Vec<IndexPosition> in descending order.
1 parent 56b3939 commit f9c34a6

File tree

3 files changed

+37
-26
lines changed

3 files changed

+37
-26
lines changed

lib/src/default_index/composite.rs

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
use std::cmp::max;
1818
use std::cmp::Ordering;
19+
use std::cmp::Reverse;
1920
use std::collections::binary_heap;
20-
use std::collections::BTreeSet;
2121
use std::collections::BinaryHeap;
2222
use std::collections::HashSet;
2323
use 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)

lib/src/default_index/mod.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,7 +1097,7 @@ mod tests {
10971097
// to (1,2) and matches the (1,2) of the first input set.
10981098
assert_eq!(
10991099
index.common_ancestors(&[id_1.clone(), id_2.clone()], &[id_5]),
1100-
vec![id_1.clone(), id_2.clone()]
1100+
vec![id_2.clone(), id_1.clone()]
11011101
);
11021102
assert_eq!(index.common_ancestors(&[id_1, id_2], &[id_3]), vec![id_0]);
11031103
}
@@ -1198,9 +1198,16 @@ mod tests {
11981198
// Multiple heads
11991199
assert_eq!(
12001200
index
1201-
.heads(&mut [id_4.clone(), id_3.clone()].iter())
1201+
.heads(&mut [id_3.clone(), id_4.clone()].iter())
12021202
.unwrap(),
1203-
vec![id_3.clone(), id_4]
1203+
vec![id_4.clone(), id_3.clone()]
1204+
);
1205+
// Duplicated inputs
1206+
assert_eq!(
1207+
index
1208+
.heads(&mut [id_4.clone(), id_3.clone(), id_4.clone()].iter())
1209+
.unwrap(),
1210+
vec![id_4.clone(), id_3.clone()]
12041211
);
12051212
// Merge commit and ancestors
12061213
assert_eq!(
@@ -1212,7 +1219,7 @@ mod tests {
12121219
index
12131220
.heads(&mut [id_5.clone(), id_3.clone()].iter())
12141221
.unwrap(),
1215-
vec![id_3.clone(), id_5.clone()]
1222+
vec![id_5.clone(), id_3.clone()]
12161223
);
12171224

12181225
assert_eq!(

lib/src/default_index/revset_engine.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use std::cell::RefCell;
1818
use std::cmp::Ordering;
1919
use std::cmp::Reverse;
20-
use std::collections::BTreeSet;
2120
use std::collections::BinaryHeap;
2221
use std::collections::HashSet;
2322
use std::fmt;
@@ -934,9 +933,8 @@ impl EvaluationContext<'_> {
934933
}
935934
ResolvedExpression::Heads(candidates) => {
936935
let candidate_set = self.evaluate(candidates)?;
937-
let head_positions: BTreeSet<_> =
936+
let positions =
938937
index.heads_pos(candidate_set.positions().attach(index).try_collect()?);
939-
let positions = head_positions.into_iter().rev().collect();
940938
Ok(Box::new(EagerRevset { positions }))
941939
}
942940
ResolvedExpression::Roots(candidates) => {
@@ -966,12 +964,8 @@ impl EvaluationContext<'_> {
966964
};
967965
let mut positions = vec![position?];
968966
for position in expression_positions_iter {
969-
positions = index
970-
.common_ancestors_pos(&positions, [position?].as_slice())
971-
.into_iter()
972-
.collect_vec();
967+
positions = index.common_ancestors_pos(&positions, &[position?]);
973968
}
974-
positions.reverse();
975969
Ok(Box::new(EagerRevset { positions }))
976970
}
977971
ResolvedExpression::Latest { candidates, count } => {

0 commit comments

Comments
 (0)