diff --git a/Cargo.toml b/Cargo.toml index bc907d4b7..992c1d5d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ test = false [dependencies] either = { version = "1.0", default-features = false } +nodrop = "0.1.8" [dev-dependencies.quickcheck] version = "0.4" diff --git a/benches/list_iterator.rs b/benches/list_iterator.rs new file mode 100644 index 000000000..2fad16bfd --- /dev/null +++ b/benches/list_iterator.rs @@ -0,0 +1,124 @@ +#![feature(test)] + +#[macro_use] +extern crate itertools; +extern crate test; + +use std::cmp::max; + +#[inline] +pub fn _max3(a: T, b: T, c: T) -> T { + max(max(a, b), c) +} + +#[inline] +pub fn _max4(a: T, b: T, c: T, d: T) -> T { + max(_max3(a, b, c), d) +} + +#[inline] +pub fn _max5(a: T, b: T, c: T, d: T, e: T) -> T { + max(_max4(a, b, c, d), e) +} + +fn gen_vec() -> Vec { + (0..1024).collect() +} + +#[bench] +fn max2(b: &mut test::Bencher) { + let x = gen_vec(); + b.iter(|| { + let mut s = 0usize; + for i in 0..x.len() - 2 { + s = s.wrapping_add(max(x[i], x[i + 1])); + } + s + }) +} + +#[bench] +fn max3(b: &mut test::Bencher) { + let x = gen_vec(); + b.iter(|| { + let mut s = 0usize; + for i in 0..x.len() - 3 { + s = s.wrapping_add(_max3(x[i], x[i + 1], x[i + 2])); + } + s + }) +} + +#[bench] +fn max4(b: &mut test::Bencher) { + let x = gen_vec(); + b.iter(|| { + let mut s = 0usize; + for i in 0..x.len() - 4 { + s = s.wrapping_add(_max4(x[i], x[i + 1], x[i + 2], x[i + 3])); + } + s + }) +} + +#[bench] +fn max5(b: &mut test::Bencher) { + let x = gen_vec(); + b.iter(|| { + let mut s = 0usize; + for i in 0..x.len() - 5 { + s = s.wrapping_add(_max5(x[i], x[i + 1], x[i + 2], x[i + 3], x[i + 4])); + } + s + }) +} + +#[bench] +fn max2_iter(b: &mut test::Bencher) { + let x = gen_vec(); + b.iter(|| { + let mut s = 0usize; + for i in 0..x.len() - 2 { + s = s.wrapping_add(iter!(x[i], x[i + 1]).max().unwrap()); + } + s + }) +} + +#[bench] +fn max3_iter(b: &mut test::Bencher) { + let x = gen_vec(); + b.iter(|| { + let mut s = 0usize; + for i in 0..x.len() - 3 { + s = s.wrapping_add(iter!(x[i], x[i + 1], x[i + 2]).max().unwrap()); + } + s + }) +} + +#[bench] +fn max4_iter(b: &mut test::Bencher) { + let x = gen_vec(); + b.iter(|| { + let mut s = 0usize; + for i in 0..x.len() - 4 { + s = s.wrapping_add(iter!(x[i], x[i + 1], x[i + 2], x[i + 3]).max().unwrap()); + } + s + }) +} + +#[bench] +fn max5_iter(b: &mut test::Bencher) { + let x = gen_vec(); + b.iter(|| { + let mut s = 0usize; + for i in 0..x.len() - 5 { + s = s.wrapping_add(iter!(x[i], x[i + 1], x[i + 2], x[i + 3], x[i + 4]) + .max() + .unwrap()); + } + s + }) +} diff --git a/src/lib.rs b/src/lib.rs index 7e10e0a8e..ae2c40c43 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ #![doc(html_root_url="https://docs.rs/itertools/")] extern crate either; +extern crate nodrop; pub use either::Either; @@ -73,7 +74,7 @@ pub mod structs { pub use peeking_take_while::PeekingTakeWhile; pub use rciter_impl::RcIter; pub use repeatn::RepeatN; - pub use sources::{RepeatCall, Unfold, Iterate}; + pub use sources::{RepeatCall, Unfold, Iterate, ListIterator}; pub use tee::Tee; pub use tuple_impl::{TupleBuffer, TupleWindows, Tuples}; pub use with_position::WithPosition; @@ -88,7 +89,7 @@ pub use diff::Diff; pub use minmax::MinMaxResult; pub use peeking_take_while::PeekingNext; pub use repeatn::repeat_n; -pub use sources::{repeat_call, unfold, iterate}; +pub use sources::{repeat_call, unfold, iterate, list_iterator}; pub use with_position::Position; pub use zip_longest::EitherOrBoth; pub use ziptuple::multizip; @@ -151,6 +152,30 @@ macro_rules! iproduct { ); } +#[macro_export] +/// Create an iterator over the specified items. +/// +/// ``` +/// #[macro_use] extern crate itertools; +/// # fn main() { +/// let mut it = iter![5, 3]; +/// assert_eq!(Some(5), it.next()); +/// assert_eq!(Some(3), it.next()); +/// assert_eq!(None, it.next()); +/// +/// assert_eq!(Some(10), itertools::max(iter![2, 10, 5, 1, 3])); +/// +/// for x in iter![4, 10, 12] { +/// // do stuff +/// } +/// # } +/// ``` +macro_rules! iter { + ($($X:expr),*) => ( + $crate::list_iterator([$($X),*]) + ); +} + #[macro_export] /// Create an iterator running multiple iterators in lockstep. /// diff --git a/src/sources.rs b/src/sources.rs index cc453a310..2746dec22 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -2,7 +2,65 @@ //! not from another iterator). use std::fmt; +use std::marker::PhantomData; use std::mem; +use std::ptr; +use nodrop::NoDrop; + +#[doc(hidden)] +pub unsafe trait FixedSizeArray: AsRef<[T]> {} + +macro_rules! impl_fixed_size_array { + ($($N:expr),*) => ( + $(unsafe impl FixedSizeArray for [T; $N] {})* + ) +} + +impl_fixed_size_array!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32); + +/// Create an iterator over a fixed number of elements. See [`iter!`](../macro.iter.html) +/// for more information. +pub struct ListIterator> { + array: NoDrop, + cur: usize, + _marker: PhantomData, +} + +#[doc(hidden)] +pub fn list_iterator>(a: A) -> ListIterator { + ListIterator { + array: NoDrop::new(a), + cur: 0, + _marker: PhantomData, + } +} + +impl> Iterator for ListIterator { + type Item = T; + + fn next(&mut self) -> Option { + let cur = &mut self.cur; + self.array.as_ref().get(*cur).map(|v| { + *cur += 1; + unsafe { ptr::read(v) } + }) + } + + fn size_hint(&self) -> (usize, Option) { + let s = self.array.as_ref().len() - self.cur; + (s, Some(s)) + } +} + +impl> ExactSizeIterator for ListIterator {} + +impl> Drop for ListIterator { + fn drop(&mut self) { + for _ in self {} + } +} + /// See [`repeat_call`](../fn.repeat_call.html) for more information. pub struct RepeatCall {