From 0781f1d00609f411b703163c5026dd56b8a1eb10 Mon Sep 17 00:00:00 2001 From: Philippe-Cholet Date: Tue, 20 Jun 2023 09:36:37 +0200 Subject: [PATCH] Merge implementations into `MergeJoinBy` with 2 additional types --- src/lib.rs | 4 +- src/merge_join.rs | 167 ++++++++++++++++++---------------------------- 2 files changed, 66 insertions(+), 105 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7107c490a..0ef9e0a26 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1065,10 +1065,10 @@ pub trait Itertools : Iterator { /// ); /// ``` #[inline] - fn merge_join_by(self, other: J, cmp_fn: F) -> MergeJoinBy + fn merge_join_by(self, other: J, cmp_fn: F) -> MergeJoinBy where J: IntoIterator, F: FnMut(&Self::Item, &J::Item) -> T, - T: merge_join::OrderingOrBool, + T: merge_join::OrderingOrBool, Self: Sized { merge_join_by(self, other, cmp_fn) diff --git a/src/merge_join.rs b/src/merge_join.rs index 0304e5f8e..983a0005a 100644 --- a/src/merge_join.rs +++ b/src/merge_join.rs @@ -1,7 +1,8 @@ use std::cmp::Ordering; use std::iter::Fuse; -use std::iter::{Peekable, FusedIterator}; +// use std::iter::FusedIterator; use std::fmt; +use std::marker::PhantomData; use either::Either; @@ -11,16 +12,22 @@ use crate::size_hint::{self, SizeHint}; #[cfg(doc)] use crate::Itertools; -pub trait MergePredicate { - fn merge_pred(&mut self, a: &T, b: &T) -> bool; +pub trait MergePredicate { + fn merge_pred(&mut self, left: &L, right: &R) -> T; +} + +impl T> MergePredicate for F { + fn merge_pred(&mut self, left: &L, right: &R) -> T { + self(left, right) + } } #[derive(Clone, Debug)] pub struct MergeLte; -impl MergePredicate for MergeLte { - fn merge_pred(&mut self, a: &T, b: &T) -> bool { - a <= b +impl MergePredicate for MergeLte { + fn merge_pred(&mut self, left: &T, right: &T) -> bool { + left <= right } } @@ -57,111 +64,43 @@ pub fn merge(i: I, j: J) -> Merge<::IntoIter, - where I: Iterator, - J: Iterator -{ - a: Peekable, - b: Peekable, - fused: Option, - cmp: F, -} - -impl fmt::Debug for MergeBy - where I: Iterator + fmt::Debug, J: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(MergeBy, a, b); -} - -implbool> MergePredicate for F { - fn merge_pred(&mut self, a: &T, b: &T) -> bool { - self(a, b) - } -} +pub type MergeBy = MergeJoinBy; /// Create a `MergeBy` iterator. pub fn merge_by_new(a: I, b: J, cmp: F) -> MergeBy where I: IntoIterator, J: IntoIterator, - F: MergePredicate, -{ - MergeBy { - a: a.into_iter().peekable(), - b: b.into_iter().peekable(), - fused: None, - cmp, - } -} - -impl Clone for MergeBy - where I: Iterator, - J: Iterator, - Peekable: Clone, - Peekable: Clone, - F: Clone + F: MergePredicate, { - clone_fields!(a, b, fused, cmp); -} - -impl Iterator for MergeBy - where I: Iterator, - J: Iterator, - F: MergePredicate -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - let less_than = match self.fused { - Some(lt) => lt, - None => match (self.a.peek(), self.b.peek()) { - (Some(a), Some(b)) => self.cmp.merge_pred(a, b), - (Some(_), None) => { - self.fused = Some(true); - true - } - (None, Some(_)) => { - self.fused = Some(false); - false - } - (None, None) => return None, - } - }; - if less_than { - self.a.next() - } else { - self.b.next() - } - } - - fn size_hint(&self) -> (usize, Option) { - // Not ExactSizeIterator because size may be larger than usize - size_hint::add(self.a.size_hint(), self.b.size_hint()) + MergeJoinBy { + left: put_back(a.into_iter().fuse()), + right: put_back(b.into_iter().fuse()), + cmp_fn: cmp, + _t: PhantomData, } } -impl FusedIterator for MergeBy - where I: FusedIterator, - J: FusedIterator, - F: MergePredicate -{} - +// impl FusedIterator for MergeBy +// where I: FusedIterator, +// J: FusedIterator, +// F: FnMut(&I::Item, &I::Item) -> bool, +// {} /// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order. /// /// [`IntoIterator`] enabled version of [`Itertools::merge_join_by`]. pub fn merge_join_by(left: I, right: J, cmp_fn: F) - -> MergeJoinBy + -> MergeJoinBy where I: IntoIterator, J: IntoIterator, F: FnMut(&I::Item, &J::Item) -> T, - T: OrderingOrBool, + T: OrderingOrBool, { MergeJoinBy { left: put_back(left.into_iter().fuse()), right: put_back(right.into_iter().fuse()), cmp_fn, + _t: PhantomData, } } @@ -169,13 +108,14 @@ pub fn merge_join_by(left: I, right: J, cmp_fn: F) /// /// See [`.merge_join_by()`](crate::Itertools::merge_join_by) for more information. #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MergeJoinBy { +pub struct MergeJoinBy { left: PutBack>, right: PutBack>, cmp_fn: F, + _t: PhantomData, } -pub trait OrderingOrBool { +pub trait OrderingOrBool { type MergeResult; fn left(left: L) -> Self::MergeResult; fn right(right: R) -> Self::MergeResult; @@ -186,7 +126,7 @@ pub trait OrderingOrBool { fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint; } -impl OrderingOrBool for Ordering { +impl OrderingOrBool for Ordering { type MergeResult = EitherOrBoth; fn left(left: L) -> Self::MergeResult { EitherOrBoth::Left(left) @@ -213,7 +153,7 @@ impl OrderingOrBool for Ordering { } } -impl OrderingOrBool for bool { +impl OrderingOrBool for bool { type MergeResult = Either; fn left(left: L) -> Self::MergeResult { Either::Left(left) @@ -234,17 +174,38 @@ impl OrderingOrBool for bool { } } -impl Clone for MergeJoinBy +impl OrderingOrBool for bool { + type MergeResult = T; + fn left(left: T) -> Self::MergeResult { + left + } + fn right(right: T) -> Self::MergeResult { + right + } + fn merge(self, left: T, right: T) -> (Option, Option, Self::MergeResult) { + if self { + (None, Some(right), left) + } else { + (Some(left), None, right) + } + } + fn size_hint(left: SizeHint, right: SizeHint) -> SizeHint { + // Not ExactSizeIterator because size may be larger than usize + size_hint::add(left, right) + } +} + +impl Clone for MergeJoinBy where I: Iterator, J: Iterator, PutBack>: Clone, PutBack>: Clone, F: Clone, { - clone_fields!(left, right, cmp_fn); + clone_fields!(left, right, cmp_fn, _t); } -impl fmt::Debug for MergeJoinBy +impl fmt::Debug for MergeJoinBy where I: Iterator + fmt::Debug, I::Item: fmt::Debug, J: Iterator + fmt::Debug, @@ -253,11 +214,11 @@ impl fmt::Debug for MergeJoinBy debug_fmt_fields!(MergeJoinBy, left, right); } -impl Iterator for MergeJoinBy +impl Iterator for MergeJoinBy where I: Iterator, J: Iterator, - F: FnMut(&I::Item, &J::Item) -> T, - T: OrderingOrBool, + F: MergePredicate, + T: OrderingOrBool, { type Item = T::MergeResult; @@ -267,7 +228,7 @@ impl Iterator for MergeJoinBy (Some(left), None) => Some(T::left(left)), (None, Some(right)) => Some(T::right(right)), (Some(left), Some(right)) => { - let (left, right, next) = (self.cmp_fn)(&left, &right).merge(left, right); + let (left, right, next) = self.cmp_fn.merge_pred(&left, &right).merge(left, right); if let Some(left) = left { self.left.put_back(left); } @@ -292,7 +253,7 @@ impl Iterator for MergeJoinBy (None, Some(_right)) => break count + 1 + self.right.into_parts().1.count(), (Some(left), Some(right)) => { count += 1; - let (left, right, _) = (self.cmp_fn)(&left, &right).merge(left, right); + let (left, right, _) = self.cmp_fn.merge_pred(&left, &right).merge(left, right); if let Some(left) = left { self.left.put_back(left); } @@ -320,7 +281,7 @@ impl Iterator for MergeJoinBy )) } (Some(left), Some(right)) => { - let (left, right, elem) = (self.cmp_fn)(&left, &right).merge(left, right); + let (left, right, elem) = self.cmp_fn.merge_pred(&left, &right).merge(left, right); if let Some(left) = left { self.left.put_back(left); } @@ -344,7 +305,7 @@ impl Iterator for MergeJoinBy (Some(_left), None) => break self.left.nth(n).map(T::left), (None, Some(_right)) => break self.right.nth(n).map(T::right), (Some(left), Some(right)) => { - let (left, right, _) = (self.cmp_fn)(&left, &right).merge(left, right); + let (left, right, _) = self.cmp_fn.merge_pred(&left, &right).merge(left, right); if let Some(left) = left { self.left.put_back(left); }