From c5d6a0dd96ad9825751ac6189fa632f521a16db2 Mon Sep 17 00:00:00 2001 From: Tim Vermeulen Date: Fri, 2 Oct 2020 05:26:36 +0200 Subject: [PATCH 1/3] Implement iter::Chain::{advance_by, advance_back_by} --- library/core/src/iter/adapters/chain.rs | 76 +++++++++++++++++++++---- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 13c6a75d58b..dadd7bfb0f7 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -115,16 +115,42 @@ where } #[inline] - fn nth(&mut self, mut n: usize) -> Option { + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + let mut rem = n; + if let Some(ref mut a) = self.a { - while let Some(x) = a.next() { - if n == 0 { - return Some(x); - } - n -= 1; + match a.advance_by(rem) { + Ok(()) => return Ok(()), + Err(k) => rem -= k, } self.a = None; } + + if let Some(ref mut b) = self.b { + match b.advance_by(rem) { + Ok(()) => return Ok(()), + Err(k) => rem -= k, + } + // we don't fuse the second iterator + } + + if rem == 0 { Ok(()) } else { Err(n - rem) } + } + + #[inline] + fn nth(&mut self, mut n: usize) -> Option { + if let Some(ref mut a) = self.a { + match a.advance_by(n) { + Ok(()) => match a.next() { + None => n = 0, + x => return x, + }, + Err(k) => n -= k, + } + + self.a = None; + } + maybe!(self.b.nth(n)) } @@ -191,16 +217,42 @@ where } #[inline] - fn nth_back(&mut self, mut n: usize) -> Option { + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + let mut rem = n; + if let Some(ref mut b) = self.b { - while let Some(x) = b.next_back() { - if n == 0 { - return Some(x); - } - n -= 1; + match b.advance_back_by(rem) { + Ok(()) => return Ok(()), + Err(k) => rem -= k, } self.b = None; } + + if let Some(ref mut a) = self.a { + match a.advance_back_by(rem) { + Ok(()) => return Ok(()), + Err(k) => rem -= k, + } + // we don't fuse the second iterator + } + + if rem == 0 { Ok(()) } else { Err(n - rem) } + } + + #[inline] + fn nth_back(&mut self, mut n: usize) -> Option { + if let Some(ref mut b) = self.b { + match b.advance_back_by(n) { + Ok(()) => match b.next_back() { + None => n = 0, + x => return x, + }, + Err(k) => n -= k, + } + + self.b = None; + } + maybe!(self.a.nth_back(n)) } From bcacfe1dbf80af7ea2e70b418e2f19c03ee09121 Mon Sep 17 00:00:00 2001 From: Tim Vermeulen Date: Fri, 2 Oct 2020 05:26:42 +0200 Subject: [PATCH 2/3] Add tests --- library/core/tests/iter.rs | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index b15d6d1b1f6..23f583e14e8 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -142,6 +142,72 @@ fn test_iterator_chain() { assert_eq!(i, expected.len()); } +#[test] +fn test_iterator_chain_advance_by() { + fn test_chain(xs: &[i32], ys: &[i32]) { + let len = xs.len() + ys.len(); + + for i in 0..xs.len() { + let mut iter = xs.iter().chain(ys); + iter.advance_by(i).unwrap(); + assert_eq!(iter.next(), Some(&xs[i])); + assert_eq!(iter.advance_by(100), Err(len - i - 1)); + } + + for i in 0..ys.len() { + let mut iter = xs.iter().chain(ys); + iter.advance_by(xs.len() + i).unwrap(); + assert_eq!(iter.next(), Some(&ys[i])); + assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1)); + } + + let mut iter = xs.iter().chain(ys); + iter.advance_by(len).unwrap(); + assert_eq!(iter.next(), None); + + let mut iter = xs.iter().chain(ys); + assert_eq!(iter.advance_by(len + 1), Err(len)); + } + + test_chain(&[], &[]); + test_chain(&[], &[0, 1, 2, 3, 4, 5]); + test_chain(&[0, 1, 2, 3, 4, 5], &[]); + test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]); +} + +#[test] +fn test_iterator_chain_advance_back_by() { + fn test_chain(xs: &[i32], ys: &[i32]) { + let len = xs.len() + ys.len(); + + for i in 0..ys.len() { + let mut iter = xs.iter().chain(ys); + iter.advance_back_by(i).unwrap(); + assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1])); + assert_eq!(iter.advance_back_by(100), Err(len - i - 1)); + } + + for i in 0..xs.len() { + let mut iter = xs.iter().chain(ys); + iter.advance_back_by(ys.len() + i).unwrap(); + assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1])); + assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1)); + } + + let mut iter = xs.iter().chain(ys); + iter.advance_back_by(len).unwrap(); + assert_eq!(iter.next_back(), None); + + let mut iter = xs.iter().chain(ys); + assert_eq!(iter.advance_back_by(len + 1), Err(len)); + } + + test_chain(&[], &[]); + test_chain(&[], &[0, 1, 2, 3, 4, 5]); + test_chain(&[0, 1, 2, 3, 4, 5], &[]); + test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]); +} + #[test] fn test_iterator_chain_nth() { let xs = [0, 1, 2, 3, 4, 5]; From 1d27a508d12a7ef1688579abb3e271b7fdcd917b Mon Sep 17 00:00:00 2001 From: Tim Vermeulen Date: Tue, 6 Oct 2020 00:48:34 +0200 Subject: [PATCH 3/3] Test with non-fused iterators --- library/core/tests/iter.rs | 45 ++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 23f583e14e8..75ca897cadc 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -4,6 +4,43 @@ use core::cell::Cell; use core::convert::TryFrom; use core::iter::*; +/// An iterator wrapper that panics whenever `next` or `next_back` is called +/// after `None` has been returned. +struct Unfuse { + iter: I, + exhausted: bool, +} + +fn unfuse(iter: I) -> Unfuse { + Unfuse { iter: iter.into_iter(), exhausted: false } +} + +impl Iterator for Unfuse +where + I: Iterator, +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + assert!(!self.exhausted); + let next = self.iter.next(); + self.exhausted = next.is_none(); + next + } +} + +impl DoubleEndedIterator for Unfuse +where + I: DoubleEndedIterator, +{ + fn next_back(&mut self) -> Option { + assert!(!self.exhausted); + let next = self.iter.next_back(); + self.exhausted = next.is_none(); + next + } +} + #[test] fn test_lt() { let empty: [isize; 0] = []; @@ -148,14 +185,14 @@ fn test_iterator_chain_advance_by() { let len = xs.len() + ys.len(); for i in 0..xs.len() { - let mut iter = xs.iter().chain(ys); + let mut iter = unfuse(xs).chain(unfuse(ys)); iter.advance_by(i).unwrap(); assert_eq!(iter.next(), Some(&xs[i])); assert_eq!(iter.advance_by(100), Err(len - i - 1)); } for i in 0..ys.len() { - let mut iter = xs.iter().chain(ys); + let mut iter = unfuse(xs).chain(unfuse(ys)); iter.advance_by(xs.len() + i).unwrap(); assert_eq!(iter.next(), Some(&ys[i])); assert_eq!(iter.advance_by(100), Err(ys.len() - i - 1)); @@ -181,14 +218,14 @@ fn test_iterator_chain_advance_back_by() { let len = xs.len() + ys.len(); for i in 0..ys.len() { - let mut iter = xs.iter().chain(ys); + let mut iter = unfuse(xs).chain(unfuse(ys)); iter.advance_back_by(i).unwrap(); assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1])); assert_eq!(iter.advance_back_by(100), Err(len - i - 1)); } for i in 0..xs.len() { - let mut iter = xs.iter().chain(ys); + let mut iter = unfuse(xs).chain(unfuse(ys)); iter.advance_back_by(ys.len() + i).unwrap(); assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1])); assert_eq!(iter.advance_back_by(100), Err(xs.len() - i - 1));