diff --git a/benches/specializations.rs b/benches/specializations.rs index 28b01cfbf..b5230a06a 100644 --- a/benches/specializations.rs +++ b/benches/specializations.rs @@ -582,29 +582,29 @@ bench_specializations! { } merge { { - let v1 = black_box(vec![0; 1024]); - let v2 = black_box(vec![0; 768]); + let v1 = black_box((0..1024).collect_vec()); + let v2 = black_box((0..768).collect_vec()); } v1.iter().merge(&v2) } merge_by { { - let v1 = black_box(vec![0; 1024]); - let v2 = black_box(vec![0; 768]); + let v1 = black_box((0..1024).collect_vec()); + let v2 = black_box((0..768).collect_vec()); } v1.iter().merge_by(&v2, PartialOrd::ge) } merge_join_by_ordering { { - let v1 = black_box(vec![0; 1024]); - let v2 = black_box(vec![0; 768]); + let v1 = black_box((0..1024).collect_vec()); + let v2 = black_box((0..768).collect_vec()); } v1.iter().merge_join_by(&v2, Ord::cmp) } merge_join_by_bool { { - let v1 = black_box(vec![0; 1024]); - let v2 = black_box(vec![0; 768]); + let v1 = black_box((0..1024).collect_vec()); + let v2 = black_box((0..768).collect_vec()); } v1.iter().merge_join_by(&v2, PartialOrd::ge) } diff --git a/src/merge_join.rs b/src/merge_join.rs index c83159186..c0de35f90 100644 --- a/src/merge_join.rs +++ b/src/merge_join.rs @@ -115,7 +115,7 @@ pub trait OrderingOrBool { // "merge" never returns (Some(...), Some(...), ...) so Option> // is appealing but it is always followed by two put_backs, so we think the compiler is // smart enough to optimize it. Or we could move put_backs into "merge". - fn merge(&mut self, left: L, right: R) -> (Option, Option, Self::MergeResult); + fn merge(&mut self, left: L, right: R) -> (Option>, Self::MergeResult); fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint; } @@ -127,11 +127,11 @@ impl Ordering> OrderingOrBool for MergeFuncLR Self::MergeResult { EitherOrBoth::Right(right) } - fn merge(&mut self, left: L, right: R) -> (Option, Option, Self::MergeResult) { + fn merge(&mut self, left: L, right: R) -> (Option>, Self::MergeResult) { match self.0(&left, &right) { - Ordering::Equal => (None, None, EitherOrBoth::Both(left, right)), - Ordering::Less => (None, Some(right), EitherOrBoth::Left(left)), - Ordering::Greater => (Some(left), None, EitherOrBoth::Right(right)), + Ordering::Equal => (None, EitherOrBoth::Both(left, right)), + Ordering::Less => (Some(Either::Right(right)), EitherOrBoth::Left(left)), + Ordering::Greater => (Some(Either::Left(left)), EitherOrBoth::Right(right)), } } fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint { @@ -154,11 +154,11 @@ impl bool> OrderingOrBool for MergeFuncLR Self::MergeResult { Either::Right(right) } - fn merge(&mut self, left: L, right: R) -> (Option, Option, Self::MergeResult) { + fn merge(&mut self, left: L, right: R) -> (Option>, Self::MergeResult) { if self.0(&left, &right) { - (None, Some(right), Either::Left(left)) + (Some(Either::Right(right)), Either::Left(left)) } else { - (Some(left), None, Either::Right(right)) + (Some(Either::Left(left)), Either::Right(right)) } } fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint { @@ -175,11 +175,11 @@ impl bool> OrderingOrBool for F { fn right(right: T) -> Self::MergeResult { right } - fn merge(&mut self, left: T, right: T) -> (Option, Option, Self::MergeResult) { + fn merge(&mut self, left: T, right: T) -> (Option>, Self::MergeResult) { if self(&left, &right) { - (None, Some(right), left) + (Some(Either::Right(right)), left) } else { - (Some(left), None, right) + (Some(Either::Left(left)), right) } } fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint { @@ -196,11 +196,11 @@ impl OrderingOrBool for MergeLte { fn right(right: T) -> Self::MergeResult { right } - fn merge(&mut self, left: T, right: T) -> (Option, Option, Self::MergeResult) { + fn merge(&mut self, left: T, right: T) -> (Option>, Self::MergeResult) { if left <= right { - (None, Some(right), left) + (Some(Either::Right(right)), left) } else { - (Some(left), None, right) + (Some(Either::Left(left)), right) } } fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint { @@ -244,66 +244,71 @@ where (Some(left), None) => Some(F::left(left)), (None, Some(right)) => Some(F::right(right)), (Some(left), Some(right)) => { - let (left, right, next) = self.cmp_fn.merge(left, right); - if let Some(left) = left { - self.left.put_back(left); - } - if let Some(right) = right { - self.right.put_back(right); + let (not_next, next) = self.cmp_fn.merge(left, right); + match not_next { + Some(Either::Left(l)) => { + self.left.put_back(l); + } + Some(Either::Right(r)) => { + self.right.put_back(r); + } + None => (), } + Some(next) } } } - fn size_hint(&self) -> SizeHint { - F::size_hint(self.left.size_hint(), self.right.size_hint()) - } + fn fold(mut self, init: B, mut f: G) -> B + where + Self: Sized, + G: FnMut(B, Self::Item) -> B, + { + let mut acc = init; + let mut left = self.left.next(); + let mut right = self.right.next(); - fn count(mut self) -> usize { - let mut count = 0; loop { - match (self.left.next(), self.right.next()) { - (None, None) => break count, - (Some(_left), None) => break count + 1 + self.left.into_parts().1.count(), - (None, Some(_right)) => break count + 1 + self.right.into_parts().1.count(), - (Some(left), Some(right)) => { - count += 1; - let (left, right, _) = self.cmp_fn.merge(left, right); - if let Some(left) = left { - self.left.put_back(left); + match (left, right) { + (Some(l), Some(r)) => match self.cmp_fn.merge(l, r) { + (Some(Either::Right(r)), x) => { + acc = f(acc, x); + left = self.left.next(); + right = Some(r); } - if let Some(right) = right { - self.right.put_back(right); + (Some(Either::Left(l)), x) => { + acc = f(acc, x); + left = Some(l); + right = self.right.next(); } + (None, x) => { + acc = f(acc, x); + left = self.left.next(); + right = self.right.next(); + } + }, + (Some(l), None) => { + self.left.put_back(l); + acc = self.left.fold(acc, |acc, x| f(acc, F::left(x))); + break; } - } - } - } - - fn last(mut self) -> Option { - let mut previous_element = None; - loop { - match (self.left.next(), self.right.next()) { - (None, None) => break previous_element, - (Some(left), None) => { - break Some(F::left(self.left.into_parts().1.last().unwrap_or(left))) - } - (None, Some(right)) => { - break Some(F::right(self.right.into_parts().1.last().unwrap_or(right))) + (None, Some(r)) => { + self.right.put_back(r); + acc = self.right.fold(acc, |acc, x| f(acc, F::right(x))); + break; } - (Some(left), Some(right)) => { - let (left, right, elem) = self.cmp_fn.merge(left, right); - if let Some(left) = left { - self.left.put_back(left); - } - if let Some(right) = right { - self.right.put_back(right); - } - previous_element = Some(elem); + (None, None) => { + break; } } } + + acc + } + + fn size_hint(&self) -> SizeHint { + F::size_hint(self.left.size_hint(), self.right.size_hint()) } fn nth(&mut self, mut n: usize) -> Option { @@ -317,12 +322,15 @@ where (Some(_left), None) => break self.left.nth(n).map(F::left), (None, Some(_right)) => break self.right.nth(n).map(F::right), (Some(left), Some(right)) => { - let (left, right, _) = self.cmp_fn.merge(left, right); - if let Some(left) = left { - self.left.put_back(left); - } - if let Some(right) = right { - self.right.put_back(right); + let (not_next, _) = self.cmp_fn.merge(left, right); + match not_next { + Some(Either::Left(l)) => { + self.left.put_back(l); + } + Some(Either::Right(r)) => { + self.right.put_back(r); + } + None => (), } } }