Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Merge/MergeBy/MergeJoinBy implementations #711

Closed
138 changes: 1 addition & 137 deletions src/adaptors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -466,142 +466,6 @@ impl<I> ExactSizeIterator for Step<I>
where I: ExactSizeIterator
{}

pub trait MergePredicate<T> {
fn merge_pred(&mut self, a: &T, b: &T) -> bool;
}

#[derive(Clone, Debug)]
pub struct MergeLte;

impl<T: PartialOrd> MergePredicate<T> 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<I, J> = MergeBy<I, J, MergeLte>;

/// 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, J>(i: I, j: J) -> Merge<<I as IntoIterator>::IntoIter, <J as IntoIterator>::IntoIter>
where I: IntoIterator,
J: IntoIterator<Item = I::Item>,
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<I, J, F>
where I: Iterator,
J: Iterator<Item = I::Item>
{
a: Peekable<I>,
b: Peekable<J>,
fused: Option<bool>,
cmp: F,
}

impl<I, J, F> fmt::Debug for MergeBy<I, J, F>
where I: Iterator + fmt::Debug, J: Iterator<Item = I::Item> + fmt::Debug,
I::Item: fmt::Debug,
{
debug_fmt_fields!(MergeBy, a, b);
}

impl<T, F: FnMut(&T, &T)->bool> MergePredicate<T> for F {
fn merge_pred(&mut self, a: &T, b: &T) -> bool {
self(a, b)
}
}

/// Create a `MergeBy` iterator.
pub fn merge_by_new<I, J, F>(a: I, b: J, cmp: F) -> MergeBy<I::IntoIter, J::IntoIter, F>
where I: IntoIterator,
J: IntoIterator<Item = I::Item>,
F: MergePredicate<I::Item>,
{
MergeBy {
a: a.into_iter().peekable(),
b: b.into_iter().peekable(),
fused: None,
cmp,
}
}

impl<I, J, F> Clone for MergeBy<I, J, F>
where I: Iterator,
J: Iterator<Item = I::Item>,
Peekable<I>: Clone,
Peekable<J>: Clone,
F: Clone
{
clone_fields!(a, b, fused, cmp);
}

impl<I, J, F> Iterator for MergeBy<I, J, F>
where I: Iterator,
J: Iterator<Item = I::Item>,
F: MergePredicate<I::Item>
{
type Item = I::Item;

fn next(&mut self) -> Option<Self::Item> {
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<usize>) {
// Not ExactSizeIterator because size may be larger than usize
size_hint::add(self.a.size_hint(), self.b.size_hint())
}
}

impl<I, J, F> FusedIterator for MergeBy<I, J, F>
where I: FusedIterator,
J: FusedIterator<Item = I::Item>,
F: MergePredicate<I::Item>
{}

/// An iterator adaptor that borrows from a `Clone`-able iterator
/// to only pick off elements while the predicate returns `true`.
///
Expand Down
3 changes: 1 addition & 2 deletions src/free.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ use crate::intersperse::{Intersperse, IntersperseWith};

pub use crate::adaptors::{
interleave,
merge,
put_back,
};
#[cfg(feature = "use_alloc")]
Expand All @@ -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;

Expand Down
7 changes: 2 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,6 @@ pub mod structs {
Batching,
MapInto,
MapOk,
Merge,
MergeBy,
TakeWhileRef,
WhileSome,
Coalesce,
Expand All @@ -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")]
Expand Down Expand Up @@ -1006,7 +1004,7 @@ pub trait Itertools : Iterator {
J: IntoIterator<Item = Self::Item>,
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
Expand Down Expand Up @@ -1070,7 +1068,6 @@ pub trait Itertools : Iterator {
fn merge_join_by<J, F, T>(self, other: J, cmp_fn: F) -> MergeJoinBy<Self, J::IntoIter, F>
where J: IntoIterator,
F: FnMut(&Self::Item, &J::Item) -> T,
T: merge_join::OrderingOrBool<Self::Item, J::Item>,
Self: Sized
{
merge_join_by(self, other, cmp_fn)
Expand Down
Loading