From 91c421cd483044cb69c356f45129318f967f6d88 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Mon, 10 Jun 2019 16:38:18 -0400 Subject: [PATCH] specialize Intersperse::fold --- benches/fold_specialization.rs | 66 ++++++++++++++++++++++++++++++++++ src/intersperse.rs | 19 ++++++++++ tests/fold_specialization.rs | 15 ++++++++ 3 files changed, 100 insertions(+) create mode 100644 benches/fold_specialization.rs create mode 100644 tests/fold_specialization.rs diff --git a/benches/fold_specialization.rs b/benches/fold_specialization.rs new file mode 100644 index 000000000..db3c99587 --- /dev/null +++ b/benches/fold_specialization.rs @@ -0,0 +1,66 @@ +#![feature(test)] + +extern crate test; +extern crate itertools; + +use itertools::Itertools; + +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() + } +} + +mod specialization { + use super::*; + + mod intersperse { + use super::*; + + #[bench] + fn external(b: &mut test::Bencher) + { + let arr = [1; 1024]; + + b.iter(|| { + let mut sum = 0; + for &x in arr.into_iter().intersperse(&0) { + sum += x; + } + sum + }) + } + + #[bench] + fn internal_specialized(b: &mut test::Bencher) + { + let arr = [1; 1024]; + + b.iter(|| { + arr.into_iter().intersperse(&0).fold(0, |acc, x| acc + x) + }) + } + + #[bench] + fn internal_unspecialized(b: &mut test::Bencher) + { + let arr = [1; 1024]; + + b.iter(|| { + Unspecialized(arr.into_iter().intersperse(&0)).fold(0, |acc, x| acc + x) + }) + } + } +} diff --git a/src/intersperse.rs b/src/intersperse.rs index b1dc73211..f82544229 100644 --- a/src/intersperse.rs +++ b/src/intersperse.rs @@ -57,4 +57,23 @@ impl Iterator for Intersperse let sh = self.iter.size_hint(); size_hint::add_scalar(size_hint::add(sh, sh), has_peek) } + + fn fold(mut self, init: B, mut f: F) -> B where + Self: Sized, F: FnMut(B, Self::Item) -> B, + { + let mut accum = init; + + if let Some(x) = self.peek.take() { + accum = f(accum, x); + } + + let element = &self.element; + + self.iter.fold(accum, + |accum, x| { + let accum = f(accum, element.clone()); + let accum = f(accum, x); + accum + }) + } } diff --git a/tests/fold_specialization.rs b/tests/fold_specialization.rs new file mode 100644 index 000000000..ac5d6a25d --- /dev/null +++ b/tests/fold_specialization.rs @@ -0,0 +1,15 @@ +extern crate itertools; + +use itertools::Itertools; + +#[test] +fn specialization_intersperse() { + let mut iter = (1..2).intersperse(0); + iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); + + let mut iter = (1..3).intersperse(0); + iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); + + let mut iter = (1..4).intersperse(0); + iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); +}