index: construct RevWalk queue after item type is settled

It doesn't make sense to build BinaryHeap with intermediate type, and I'm
going to reimplement take_until_roots() in a way that the queue drops
uninteresting items.
This commit is contained in:
Yuya Nishihara 2024-03-08 20:12:03 +09:00
parent 8480ee9e05
commit 34fbaaaad6

View file

@ -110,16 +110,6 @@ impl<P, T> RevWalkWorkItem<P, T> {
fn is_wanted(&self) -> bool { fn is_wanted(&self) -> bool {
matches!(self.state, RevWalkWorkItemState::Wanted(_)) matches!(self.state, RevWalkWorkItemState::Wanted(_))
} }
fn map_wanted<U>(self, f: impl FnOnce(T) -> U) -> RevWalkWorkItem<P, U> {
RevWalkWorkItem {
pos: self.pos,
state: match self.state {
RevWalkWorkItemState::Wanted(t) => RevWalkWorkItemState::Wanted(f(t)),
RevWalkWorkItemState::Unwanted => RevWalkWorkItemState::Unwanted,
},
}
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -136,17 +126,6 @@ impl<P: Ord, T: Ord> RevWalkQueue<P, T> {
} }
} }
fn map_wanted<U: Ord>(self, mut f: impl FnMut(T) -> U) -> RevWalkQueue<P, U> {
RevWalkQueue {
items: self
.items
.into_iter()
.map(|x| x.map_wanted(&mut f))
.collect(),
unwanted_count: self.unwanted_count,
}
}
fn push_wanted(&mut self, pos: P, t: T) { fn push_wanted(&mut self, pos: P, t: T) {
let state = RevWalkWorkItemState::Wanted(t); let state = RevWalkWorkItemState::Wanted(t);
self.items.push(RevWalkWorkItem { pos, state }); self.items.push(RevWalkWorkItem { pos, state });
@ -203,34 +182,38 @@ impl<P: Ord, T: Ord> RevWalkQueue<P, T> {
#[must_use] #[must_use]
pub(super) struct RevWalkBuilder<'a> { pub(super) struct RevWalkBuilder<'a> {
index: CompositeIndex<'a>, index: CompositeIndex<'a>,
// TODO: Use Vec<_> until queued item type is settled. wanted: Vec<IndexPosition>,
queue: RevWalkQueue<IndexPosition, ()>, unwanted: Vec<IndexPosition>,
} }
impl<'a> RevWalkBuilder<'a> { impl<'a> RevWalkBuilder<'a> {
pub fn new(index: CompositeIndex<'a>) -> Self { pub fn new(index: CompositeIndex<'a>) -> Self {
let queue = RevWalkQueue::new(); RevWalkBuilder {
RevWalkBuilder { index, queue } index,
wanted: Vec::new(),
unwanted: Vec::new(),
}
} }
/// Adds head positions to be included. /// Adds head positions to be included.
pub fn wanted_heads(mut self, positions: impl IntoIterator<Item = IndexPosition>) -> Self { pub fn wanted_heads(mut self, positions: impl IntoIterator<Item = IndexPosition>) -> Self {
self.queue.extend_wanted(positions, ()); self.wanted.extend(positions);
self self
} }
/// Adds root positions to be excluded. The roots precede the heads. /// Adds root positions to be excluded. The roots precede the heads.
pub fn unwanted_roots(mut self, positions: impl IntoIterator<Item = IndexPosition>) -> Self { pub fn unwanted_roots(mut self, positions: impl IntoIterator<Item = IndexPosition>) -> Self {
self.queue.extend_unwanted(positions); self.unwanted.extend(positions);
self self
} }
/// Walks ancestors. /// Walks ancestors.
pub fn ancestors(self) -> RevWalkAncestors<'a> { pub fn ancestors(self) -> RevWalkAncestors<'a> {
RevWalkImpl { let index = self.index;
index: self.index, let mut queue = RevWalkQueue::new();
queue: self.queue, queue.extend_wanted(self.wanted, ());
} queue.extend_unwanted(self.unwanted);
RevWalkImpl { index, queue }
} }
/// Walks ancestors within the `generation_range`. /// Walks ancestors within the `generation_range`.
@ -240,7 +223,16 @@ impl<'a> RevWalkBuilder<'a> {
self, self,
generation_range: Range<u32>, generation_range: Range<u32>,
) -> RevWalkAncestorsGenerationRange<'a> { ) -> RevWalkAncestorsGenerationRange<'a> {
RevWalkGenerationRangeImpl::new(self.index, self.queue, generation_range) let index = self.index;
let mut queue = RevWalkQueue::new();
let item_range = RevWalkItemGenerationRange::from_filter_range(generation_range.clone());
queue.extend_wanted(self.wanted, Reverse(item_range));
queue.extend_unwanted(self.unwanted);
RevWalkGenerationRangeImpl {
index,
queue,
generation_end: generation_range.end,
}
} }
/// Walks ancestors until all of the reachable roots in `root_positions` get /// Walks ancestors until all of the reachable roots in `root_positions` get
@ -293,14 +285,20 @@ impl<'a> RevWalkBuilder<'a> {
let root_positions = Vec::from_iter(root_positions); let root_positions = Vec::from_iter(root_positions);
let entries = self.ancestors_until_roots(&root_positions); let entries = self.ancestors_until_roots(&root_positions);
let descendants_index = RevWalkDescendantsIndex::build(index, entries); let descendants_index = RevWalkDescendantsIndex::build(index, entries);
let mut queue = RevWalkQueue::new(); let mut queue = RevWalkQueue::new();
let item_range = RevWalkItemGenerationRange::from_filter_range(generation_range.clone());
for pos in root_positions { for pos in root_positions {
// Do not add unreachable roots which shouldn't be visited // Do not add unreachable roots which shouldn't be visited
if descendants_index.contains_pos(pos) { if descendants_index.contains_pos(pos) {
queue.push_wanted(Reverse(pos), ()); queue.push_wanted(Reverse(pos), Reverse(item_range));
} }
} }
RevWalkGenerationRangeImpl::new(descendants_index, queue, generation_range) RevWalkGenerationRangeImpl {
index: descendants_index,
queue,
generation_end: generation_range.end,
}
} }
} }
@ -358,26 +356,6 @@ pub(super) struct RevWalkGenerationRangeImpl<'a, I: RevWalkIndex<'a>> {
} }
impl<'a, I: RevWalkIndex<'a>> RevWalkGenerationRangeImpl<'a, I> { impl<'a, I: RevWalkIndex<'a>> RevWalkGenerationRangeImpl<'a, I> {
fn new(index: I, queue: RevWalkQueue<I::Position, ()>, generation_range: Range<u32>) -> Self {
// Translate filter range to item ranges so that overlapped ranges can be
// merged later.
//
// Example: `generation_range = 1..4`
// (original) (translated)
// 0 1 2 3 4 0 1 2 3 4
// *=====o generation_range + generation_end
// + : : item's generation o=====* : item's range
let item_range = RevWalkItemGenerationRange {
start: 0,
end: u32::saturating_sub(generation_range.end, generation_range.start),
};
RevWalkGenerationRangeImpl {
index,
queue: queue.map_wanted(|()| Reverse(item_range)),
generation_end: generation_range.end,
}
}
fn enqueue_wanted_adjacents( fn enqueue_wanted_adjacents(
&mut self, &mut self,
entry: &IndexEntry<'_>, entry: &IndexEntry<'_>,
@ -452,6 +430,23 @@ struct RevWalkItemGenerationRange {
} }
impl RevWalkItemGenerationRange { impl RevWalkItemGenerationRange {
/// Translates filter range to item range so that overlapped ranges can be
/// merged later.
///
/// Example: `generation_range = 1..4`
/// ```text
/// (original) (translated)
/// 0 1 2 3 4 0 1 2 3 4
/// *=====o generation_range + generation_end
/// + : : item's generation o=====* : item's range
/// ```
fn from_filter_range(range: Range<u32>) -> Self {
RevWalkItemGenerationRange {
start: 0,
end: u32::saturating_sub(range.end, range.start),
}
}
/// Suppose sorted ranges `self, other`, merges them if overlapped. /// Suppose sorted ranges `self, other`, merges them if overlapped.
#[must_use] #[must_use]
fn try_merge_end(self, other: Self) -> Option<Self> { fn try_merge_end(self, other: Self) -> Option<Self> {