diff --git a/src/merge_join.rs b/src/merge_join.rs index cbbeb28d0..e2bbc0a87 100644 --- a/src/merge_join.rs +++ b/src/merge_join.rs @@ -31,6 +31,23 @@ pub struct MergeJoinBy { cmp_fn: F } +impl Clone for MergeJoinBy +where + I: Iterator, + J: Iterator, + PutBack>: Clone, + PutBack>: Clone, + F: Clone, +{ + fn clone(&self) -> Self { + MergeJoinBy { + left: self.left.clone(), + right: self.right.clone(), + cmp_fn: self.cmp_fn.clone(), + } + } +} + impl fmt::Debug for MergeJoinBy where I: Iterator + fmt::Debug, I::Item: fmt::Debug, diff --git a/tests/specializations.rs b/tests/specializations.rs new file mode 100644 index 000000000..719e348f8 --- /dev/null +++ b/tests/specializations.rs @@ -0,0 +1,111 @@ +extern crate itertools; + +use itertools::{Itertools, EitherOrBoth}; + +use std::fmt::Debug; +use std::ops::BitXor; + +struct Unspecialized(I); +impl Iterator for Unspecialized +where + I: Iterator, +{ + type Item = I::Item; + + #[inline(always)] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline(always)] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} + +fn check_specialized<'a, V, IterItem, Iter, F>(iterator: &Iter, mapper: F) +where + V: Eq + Debug, + IterItem: 'a, + Iter: Iterator + Clone + 'a, + F: Fn(Box + 'a>) -> V, +{ + assert_eq!( + mapper(Box::new(Unspecialized(iterator.clone()))), + mapper(Box::new(iterator.clone())) + ) +} + +fn check_specialized_count_last_nth_sizeh<'a, IterItem, Iter>(it: &Iter, expected_size: usize) +where + IterItem: 'a + Eq + Debug, + Iter: Iterator + Clone + 'a, +{ + let size = it.clone().count(); + assert_eq!(size, expected_size); + check_specialized(it, |i| i.count()); + check_specialized(it, |i| i.last()); + for n in 0..size + 2 { + check_specialized(it, |mut i| i.nth(n)); + } + let mut it_sh = it.clone(); + for n in 0..size + 2 { + let len = it_sh.clone().count(); + let (min, max) = it_sh.size_hint(); + assert_eq!((size-n.min(size)), len); + assert!(min <= len); + if let Some(max) = max { + assert!(len <= max); + } + it_sh.next(); + } +} + +fn check_specialized_fold_xor<'a, IterItem, Iter>(it: &Iter) +where + IterItem: 'a + + BitXor + + Eq + + Debug + + BitXor<::Output, Output = ::Output> + + Clone, + ::Output: + BitXor::Output> + Eq + Debug + Clone, + Iter: Iterator + Clone + 'a, +{ + check_specialized(it, |mut i| { + let first = i.next().map(|f| f.clone() ^ (f.clone() ^ f)); + i.fold(first, |acc, v: IterItem| acc.map(move |a| v ^ a)) + }); +} + +#[test] +fn put_back() { + let test_vec = vec![7, 4, 1]; + { + // Lexical lifetimes support + let pb = itertools::put_back(test_vec.iter()); + check_specialized_count_last_nth_sizeh(&pb, 3); + check_specialized_fold_xor(&pb); + } + + let mut pb = itertools::put_back(test_vec.into_iter()); + pb.put_back(1); + check_specialized_count_last_nth_sizeh(&pb, 4); + check_specialized_fold_xor(&pb); +} + +#[test] +fn merge_join_by() { + let i1 = vec![1, 3, 5].into_iter(); + let i2 = vec![0, 3, 4, 5].into_iter(); + let mjb = i1.merge_join_by(i2, std::cmp::Ord::cmp); + check_specialized_count_last_nth_sizeh(&mjb, 5); + // Rust 1.24 compatibility: + fn eob_left_z(eob: EitherOrBoth) -> usize { eob.left().unwrap_or(0) } + fn eob_right_z(eob: EitherOrBoth) -> usize { eob.left().unwrap_or(0) } + fn eob_both_z(eob: EitherOrBoth) -> usize { let (a,b) = eob.both().unwrap_or((0,0)); assert_eq!(a,b); a } + check_specialized_fold_xor(&mjb.clone().map(eob_left_z)); + check_specialized_fold_xor(&mjb.clone().map(eob_right_z)); + check_specialized_fold_xor(&mjb.clone().map(eob_both_z)); +}