diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 1695bbd65..a02c6b6e0 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -15,7 +15,7 @@ pub use self::map::MapResults; pub use self::multi_product::*; use std::fmt; -use std::iter::{Fuse, Peekable, FromIterator, FusedIterator}; +use std::iter::{Fuse, FromIterator, FusedIterator}; use std::marker::PhantomData; use crate::size_hint; @@ -466,142 +466,6 @@ impl ExactSizeIterator for Step where I: ExactSizeIterator {} -pub trait MergePredicate { - fn merge_pred(&mut self, a: &T, b: &T) -> bool; -} - -#[derive(Clone, Debug)] -pub struct MergeLte; - -impl MergePredicate for MergeLte { - fn merge_pred(&mut self, a: &T, b: &T) -> bool { - a <= b - } -} - -/// An iterator adaptor that merges the two base iterators in ascending order. -/// If both base iterators are sorted (ascending), the result is sorted. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.merge()`](crate::Itertools::merge_by) for more information. -pub type Merge = MergeBy; - -/// Create an iterator that merges elements in `i` and `j`. -/// -/// [`IntoIterator`] enabled version of [`Itertools::merge`](crate::Itertools::merge). -/// -/// ``` -/// use itertools::merge; -/// -/// for elt in merge(&[1, 2, 3], &[2, 3, 4]) { -/// /* loop body */ -/// } -/// ``` -pub fn merge(i: I, j: J) -> Merge<::IntoIter, ::IntoIter> - where I: IntoIterator, - J: IntoIterator, - I::Item: PartialOrd -{ - merge_by_new(i, j, MergeLte) -} - -/// An iterator adaptor that merges the two base iterators in ascending order. -/// If both base iterators are sorted (ascending), the result is sorted. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.merge_by()`](crate::Itertools::merge_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MergeBy - 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) - } -} - -/// 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 -{ - 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()) - } -} - -impl FusedIterator for MergeBy - where I: FusedIterator, - J: FusedIterator, - F: MergePredicate -{} - /// An iterator adaptor that borrows from a `Clone`-able iterator /// to only pick off elements while the predicate returns `true`. /// diff --git a/src/free.rs b/src/free.rs index 19e3e2869..c9a87cd0a 100644 --- a/src/free.rs +++ b/src/free.rs @@ -19,7 +19,6 @@ use crate::intersperse::{Intersperse, IntersperseWith}; pub use crate::adaptors::{ interleave, - merge, put_back, }; #[cfg(feature = "use_alloc")] @@ -31,7 +30,7 @@ pub use crate::peek_nth::peek_nth; #[cfg(feature = "use_alloc")] pub use crate::kmerge_impl::kmerge; pub use crate::zip_eq_impl::zip_eq; -pub use crate::merge_join::merge_join_by; +pub use crate::merge_join::{merge, merge_join_by}; #[cfg(feature = "use_alloc")] pub use crate::rciter_impl::rciter; diff --git a/src/lib.rs b/src/lib.rs index 41bedfcab..9b7002486 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,8 +99,6 @@ pub mod structs { Batching, MapInto, MapOk, - Merge, - MergeBy, TakeWhileRef, WhileSome, Coalesce, @@ -127,7 +125,7 @@ pub mod structs { pub use crate::intersperse::{Intersperse, IntersperseWith}; #[cfg(feature = "use_alloc")] pub use crate::kmerge_impl::{KMerge, KMergeBy}; - pub use crate::merge_join::MergeJoinBy; + pub use crate::merge_join::{Merge, MergeBy, MergeJoinBy}; #[cfg(feature = "use_alloc")] pub use crate::multipeek_impl::MultiPeek; #[cfg(feature = "use_alloc")] @@ -1008,7 +1006,7 @@ pub trait Itertools : Iterator { J: IntoIterator, F: FnMut(&Self::Item, &Self::Item) -> bool { - adaptors::merge_by_new(self, other.into_iter(), is_first) + merge_join::merge_by_new(self, other.into_iter(), is_first) } /// Create an iterator that merges items from both this and the specified diff --git a/src/merge_join.rs b/src/merge_join.rs index 84f7d0333..0304e5f8e 100644 --- a/src/merge_join.rs +++ b/src/merge_join.rs @@ -1,5 +1,6 @@ use std::cmp::Ordering; use std::iter::Fuse; +use std::iter::{Peekable, FusedIterator}; use std::fmt; use either::Either; @@ -10,6 +11,143 @@ use crate::size_hint::{self, SizeHint}; #[cfg(doc)] use crate::Itertools; +pub trait MergePredicate { + fn merge_pred(&mut self, a: &T, b: &T) -> bool; +} + +#[derive(Clone, Debug)] +pub struct MergeLte; + +impl MergePredicate for MergeLte { + fn merge_pred(&mut self, a: &T, b: &T) -> bool { + a <= b + } +} + +/// An iterator adaptor that merges the two base iterators in ascending order. +/// If both base iterators are sorted (ascending), the result is sorted. +/// +/// Iterator element type is `I::Item`. +/// +/// See [`.merge()`](crate::Itertools::merge_by) for more information. +pub type Merge = MergeBy; + +/// Create an iterator that merges elements in `i` and `j`. +/// +/// [`IntoIterator`] enabled version of [`Itertools::merge`](crate::Itertools::merge). +/// +/// ``` +/// use itertools::merge; +/// +/// for elt in merge(&[1, 2, 3], &[2, 3, 4]) { +/// /* loop body */ +/// } +/// ``` +pub fn merge(i: I, j: J) -> Merge<::IntoIter, ::IntoIter> + where I: IntoIterator, + J: IntoIterator, + I::Item: PartialOrd +{ + merge_by_new(i, j, MergeLte) +} + +/// An iterator adaptor that merges the two base iterators in ascending order. +/// If both base iterators are sorted (ascending), the result is sorted. +/// +/// Iterator element type is `I::Item`. +/// +/// See [`.merge_by()`](crate::Itertools::merge_by) for more information. +#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] +pub struct MergeBy + 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) + } +} + +/// 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 +{ + 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()) + } +} + +impl FusedIterator for MergeBy + where I: FusedIterator, + J: FusedIterator, + F: MergePredicate +{} + + /// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order. /// /// [`IntoIterator`] enabled version of [`Itertools::merge_join_by`].