From c64f96361eec3f5ad1b1fe5b46583a0a4b15bd06 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Mon, 5 Aug 2013 19:20:37 -0700 Subject: [PATCH 1/2] Implement .size_hint() on new vec iterators --- src/libstd/vec.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 7c8046a64b2..e69cb1341bf 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -65,7 +65,7 @@ use cmp; use iterator::*; use libc::c_void; -use num::Zero; +use num::{Integer, Zero, CheckedAdd, Saturating}; use option::{None, Option, Some}; use ptr::to_unsafe_ptr; use ptr; @@ -209,6 +209,7 @@ pub struct SplitIterator<'self, T> { } impl<'self, T> Iterator<&'self [T]> for SplitIterator<'self, T> { + #[inline] fn next(&mut self) -> Option<&'self [T]> { if self.finished { return None; } @@ -230,6 +231,21 @@ fn next(&mut self) -> Option<&'self [T]> { } } } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + if self.finished { + return (0, Some(0)) + } + // if the predicate doesn't match anything, we yield one slice + // if it matches every element, we yield N+1 empty slices where + // N is either the number of elements or the number of splits. + match (self.v.len(), self.n) { + (0,_) => (1, Some(1)), + (_,0) => (1, Some(1)), + (l,n) => (1, cmp::min(l,n).checked_add(&1u)) + } + } } /// An iterator over the slices of a vector separated by elements that @@ -242,6 +258,7 @@ pub struct RSplitIterator<'self, T> { } impl<'self, T> Iterator<&'self [T]> for RSplitIterator<'self, T> { + #[inline] fn next(&mut self) -> Option<&'self [T]> { if self.finished { return None; } @@ -263,6 +280,18 @@ fn next(&mut self) -> Option<&'self [T]> { } } } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + if self.finished { + return (0, Some(0)) + } + match (self.v.len(), self.n) { + (0,_) => (1, Some(1)), + (_,0) => (1, Some(1)), + (l,n) => (1, cmp::min(l,n).checked_add(&1u)) + } + } } // Appending @@ -453,6 +482,7 @@ pub struct WindowIter<'self, T> { } impl<'self, T> Iterator<&'self [T]> for WindowIter<'self, T> { + #[inline] fn next(&mut self) -> Option<&'self [T]> { if self.size > self.v.len() { None @@ -462,6 +492,16 @@ fn next(&mut self) -> Option<&'self [T]> { ret } } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + if self.size > self.v.len() { + (0, Some(0)) + } else { + let x = self.v.len() - self.size; + (x.saturating_add(1), x.checked_add(&1u)) + } + } } /// An iterator over a vector in (non-overlapping) chunks (`size` @@ -476,6 +516,7 @@ pub struct ChunkIter<'self, T> { } impl<'self, T> Iterator<&'self [T]> for ChunkIter<'self, T> { + #[inline] fn next(&mut self) -> Option<&'self [T]> { if self.v.len() == 0 { None @@ -487,9 +528,21 @@ fn next(&mut self) -> Option<&'self [T]> { Some(fst) } } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + if self.v.len() == 0 { + (0, Some(0)) + } else { + let (n, rem) = self.v.len().div_rem(&self.size); + let n = if rem > 0 { n+1 } else { n }; + (n, Some(n)) + } + } } impl<'self, T> DoubleEndedIterator<&'self [T]> for ChunkIter<'self, T> { + #[inline] fn next_back(&mut self) -> Option<&'self [T]> { if self.v.len() == 0 { None @@ -2223,6 +2276,7 @@ fn indexable(&self) -> uint { exact } + #[inline] fn idx(&self, index: uint) -> Option<&'self T> { unsafe { if index < self.indexable() { @@ -2268,6 +2322,7 @@ pub struct MoveIterator { } impl Iterator for MoveIterator { + #[inline] fn next(&mut self) -> Option { // this is peculiar, but is required for safety with respect // to dtors. It traverses the first half of the vec, and @@ -2285,6 +2340,12 @@ fn next(&mut self) -> Option { self.v.pop_opt() } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + let l = self.v.len(); + (l, Some(l)) + } } /// An iterator that moves out of a vector in reverse order. @@ -2294,9 +2355,16 @@ pub struct MoveRevIterator { } impl Iterator for MoveRevIterator { + #[inline] fn next(&mut self) -> Option { self.v.pop_opt() } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + let l = self.v.len(); + (l, Some(l)) + } } impl FromIterator for ~[A] { From 8741770471d08c78780fd6c22c18c0cf28fcf074 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Sun, 18 Aug 2013 21:47:43 -0700 Subject: [PATCH 2/2] Update size_hint()s on std::iterator Iterators Add size_hint() to a few Iterators that were missing it. Update a couple of existing size_hint()s to use checked_add() instead of saturating_add() for the upper bound. --- src/libstd/iterator.rs | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 1d32c5df14e..7425da97368 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -18,7 +18,7 @@ */ use cmp; -use num::{Zero, One, Integer, Saturating}; +use num::{Zero, One, Integer, CheckedAdd, Saturating}; use option::{Option, Some, None}; use ops::{Add, Mul, Sub}; use cmp::Ord; @@ -817,7 +817,7 @@ fn size_hint(&self) -> (uint, Option) { let lower = a_lower.saturating_add(b_lower); let upper = match (a_upper, b_upper) { - (Some(x), Some(y)) => Some(x.saturating_add(y)), + (Some(x), Some(y)) => x.checked_add(&y), _ => None }; @@ -1094,6 +1094,21 @@ fn next(&mut self) -> Option { if self.peeked.is_some() { self.peeked.take() } else { self.iter.next() } } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + let (lo, hi) = self.iter.size_hint(); + if self.peeked.is_some() { + let lo = lo.saturating_add(1); + let hi = match hi { + Some(x) => x.checked_add(&1), + None => None + }; + (lo, hi) + } else { + (lo, hi) + } + } } impl<'self, A, T: Iterator> Peekable { @@ -1101,15 +1116,12 @@ impl<'self, A, T: Iterator> Peekable { /// or None if the iterator is exhausted. #[inline] pub fn peek(&'self mut self) -> Option<&'self A> { + if self.peeked.is_none() { + self.peeked = self.iter.next(); + } match self.peeked { Some(ref value) => Some(value), - None => { - self.peeked = self.iter.next(); - match self.peeked { - Some(ref value) => Some(value), - None => None, - } - }, + None => None, } } } @@ -1355,7 +1367,7 @@ fn size_hint(&self) -> (uint, Option) { let (blo, bhi) = self.backiter.map_default((0, Some(0)), |it| it.size_hint()); let lo = flo.saturating_add(blo); match (self.iter.size_hint(), fhi, bhi) { - ((0, Some(0)), Some(a), Some(b)) => (lo, Some(a.saturating_add(b))), + ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(&b)), _ => (lo, None) } } @@ -1461,6 +1473,12 @@ impl<'self, A, St> Iterator for Unfoldr<'self, A, St> { fn next(&mut self) -> Option { (self.f)(&mut self.state) } + + #[inline] + fn size_hint(&self) -> (uint, Option) { + // no possible known bounds at this point + (0, None) + } } /// An infinite iterator starting at `start` and advancing by `step` with each @@ -1504,6 +1522,9 @@ fn next(&mut self) -> Option { None } } + + // FIXME: #8606 Implement size_hint() on Range + // Blocked on #8605 Need numeric trait for converting to `Option` } impl + Integer + Ord + Clone> DoubleEndedIterator for Range {