diff --git a/lib/src/default_index/revset_engine.rs b/lib/src/default_index/revset_engine.rs index 15de39cd0..240c6cbea 100644 --- a/lib/src/default_index/revset_engine.rs +++ b/lib/src/default_index/revset_engine.rs @@ -338,10 +338,11 @@ where &'a self, index: CompositeIndex<'index>, ) -> Box> + 'a> { - Box::new(UnionRevsetIterator { - iter1: self.set1.iter(index).peekable(), - iter2: self.set2.iter(index).peekable(), - }) + Box::new(union_by( + self.set1.iter(index), + self.set2.iter(index), + |entry1, entry2| entry1.position().cmp(&entry2.position()), + )) } fn into_predicate<'a>(self: Box) -> Box @@ -367,27 +368,32 @@ where } } -struct UnionRevsetIterator { +/// Iterator that merges two sorted iterators. +/// +/// The input items should be sorted in descending order by the `cmp` function. +struct UnionByIterator { iter1: Peekable, iter2: Peekable, + cmp: C, } -impl<'index, I1, I2> Iterator for UnionRevsetIterator +impl Iterator for UnionByIterator where - I1: Iterator>, - I2: Iterator>, + I1: Iterator, + I2: Iterator, + C: FnMut(&I1::Item, &I2::Item) -> Ordering, { - type Item = IndexEntry<'index>; + type Item = I1::Item; fn next(&mut self) -> Option { match (self.iter1.peek(), self.iter2.peek()) { (None, _) => self.iter2.next(), (_, None) => self.iter1.next(), - (Some(entry1), Some(entry2)) => match entry1.position().cmp(&entry2.position()) { + (Some(item1), Some(item2)) => match (self.cmp)(item1, item2) { Ordering::Less => self.iter2.next(), Ordering::Equal => { - self.iter1.next(); - self.iter2.next() + self.iter2.next(); + self.iter1.next() } Ordering::Greater => self.iter1.next(), }, @@ -395,6 +401,23 @@ where } } +fn union_by( + iter1: I1, + iter2: I2, + cmp: C, +) -> UnionByIterator +where + I1: IntoIterator, + I2: IntoIterator, + C: FnMut(&I1::Item, &I2::Item) -> Ordering, +{ + UnionByIterator { + iter1: iter1.into_iter().peekable(), + iter2: iter2.into_iter().peekable(), + cmp, + } +} + #[derive(Debug)] struct IntersectionRevset { set1: S1, @@ -410,10 +433,11 @@ where &'a self, index: CompositeIndex<'index>, ) -> Box> + 'a> { - Box::new(IntersectionRevsetIterator { - iter1: self.set1.iter(index).peekable(), - iter2: self.set2.iter(index).peekable(), - }) + Box::new(intersection_by( + self.set1.iter(index), + self.set2.iter(index), + |entry1, entry2| entry1.position().cmp(&entry2.position()), + )) } fn into_predicate<'a>(self: Box) -> Box @@ -439,17 +463,22 @@ where } } -struct IntersectionRevsetIterator { +/// Iterator that intersects two sorted iterators. +/// +/// The input items should be sorted in descending order by the `cmp` function. +struct IntersectionByIterator { iter1: Peekable, iter2: Peekable, + cmp: C, } -impl<'index, I1, I2> Iterator for IntersectionRevsetIterator +impl Iterator for IntersectionByIterator where - I1: Iterator>, - I2: Iterator>, + I1: Iterator, + I2: Iterator, + C: FnMut(&I1::Item, &I2::Item) -> Ordering, { - type Item = IndexEntry<'index>; + type Item = I1::Item; fn next(&mut self) -> Option { loop { @@ -460,13 +489,13 @@ where (_, None) => { return None; } - (Some(entry1), Some(entry2)) => match entry1.position().cmp(&entry2.position()) { + (Some(item1), Some(item2)) => match (self.cmp)(item1, item2) { Ordering::Less => { self.iter2.next(); } Ordering::Equal => { - self.iter1.next(); - return self.iter2.next(); + self.iter2.next(); + return self.iter1.next(); } Ordering::Greater => { self.iter1.next(); @@ -477,6 +506,23 @@ where } } +fn intersection_by( + iter1: I1, + iter2: I2, + cmp: C, +) -> IntersectionByIterator +where + I1: IntoIterator, + I2: IntoIterator, + C: FnMut(&I1::Item, &I2::Item) -> Ordering, +{ + IntersectionByIterator { + iter1: iter1.into_iter().peekable(), + iter2: iter2.into_iter().peekable(), + cmp, + } +} + #[derive(Debug)] struct DifferenceRevset { // The minuend (what to subtract from) @@ -494,10 +540,11 @@ where &'a self, index: CompositeIndex<'index>, ) -> Box> + 'a> { - Box::new(DifferenceRevsetIterator { - iter1: self.set1.iter(index).peekable(), - iter2: self.set2.iter(index).peekable(), - }) + Box::new(difference_by( + self.set1.iter(index), + self.set2.iter(index), + |entry1, entry2| entry1.position().cmp(&entry2.position()), + )) } fn into_predicate<'a>(self: Box) -> Box @@ -523,17 +570,22 @@ where } } -struct DifferenceRevsetIterator { +/// Iterator that subtracts `iter2` items from `iter1`. +/// +/// The input items should be sorted in descending order by the `cmp` function. +struct DifferenceByIterator { iter1: Peekable, iter2: Peekable, + cmp: C, } -impl<'index, I1, I2> Iterator for DifferenceRevsetIterator +impl Iterator for DifferenceByIterator where - I1: Iterator>, - I2: Iterator>, + I1: Iterator, + I2: Iterator, + C: FnMut(&I1::Item, &I2::Item) -> Ordering, { - type Item = IndexEntry<'index>; + type Item = I1::Item; fn next(&mut self) -> Option { loop { @@ -544,7 +596,7 @@ where (_, None) => { return self.iter1.next(); } - (Some(entry1), Some(entry2)) => match entry1.position().cmp(&entry2.position()) { + (Some(item1), Some(item2)) => match (self.cmp)(item1, item2) { Ordering::Less => { self.iter2.next(); } @@ -561,6 +613,23 @@ where } } +fn difference_by( + iter1: I1, + iter2: I2, + cmp: C, +) -> DifferenceByIterator +where + I1: IntoIterator, + I2: IntoIterator, + C: FnMut(&I1::Item, &I2::Item) -> Ordering, +{ + DifferenceByIterator { + iter1: iter1.into_iter().peekable(), + iter2: iter2.into_iter().peekable(), + cmp, + } +} + pub fn evaluate( expression: &ResolvedExpression, store: &Arc,