From 4b2cc22031d56a4846bc0ad4e65e19892db734c4 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 30 Aug 2013 19:59:49 +0200 Subject: [PATCH 1/9] std::iterator: Introduce trait ExactSizeHint The trait `ExactSizeHint` is introduced to solve a few small niggles: * We can't reverse (`.invert()`) an enumeration iterator * for a vector, we have `v.iter().position(f)` but `v.rposition(f)`. * We can't reverse `Zip` even if both iterators are from vectors `ExactSizeHint` is an empty trait that is intended to indicate that an iterator, for example `VecIterator`, knows its exact finite size and reports it correctly using `.size_hint()`. Only adaptors that preserve this at all times, can expose this trait further. (Where here we say finite for fitting in uint). --- src/libstd/iterator.rs | 35 +++++++++++++++++++++++++++++++++++ src/libstd/vec.rs | 3 +++ 2 files changed, 38 insertions(+) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 4af7b3e242596..19596421cb285 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -616,6 +616,26 @@ pub trait RandomAccessIterator: Iterator { fn idx(&self, index: uint) -> Option; } +/// An iterator that knows its exact length +/// +/// This trait is a helper for iterators like the vector iterator, so that +/// it can support double-ended enumeration. +/// +/// `Iterator::size_hint` *must* return the exact size of the iterator. +/// Note that the size must fit in `uint`. +pub trait ExactSizeHint {} + +// All adaptors that preserve the size of the wrapped iterator are fine +// Adaptors that may overflow in `size_hint` are not, i.e. `Chain`. +impl ExactSizeHint for Enumerate {} +impl<'self, A, T: ExactSizeHint> ExactSizeHint for Inspect<'self, A, T> {} +impl ExactSizeHint for Invert {} +impl<'self, A, B, T: ExactSizeHint> ExactSizeHint for Map<'self, A, B, T> {} +impl ExactSizeHint for Peekable {} +impl ExactSizeHint for Skip {} +impl ExactSizeHint for Take {} +impl ExactSizeHint for Zip {} + /// An double-ended iterator with the direction inverted #[deriving(Clone)] pub struct Invert { @@ -1094,6 +1114,21 @@ impl> Iterator<(uint, A)> for Enumerate { } } +impl + ExactSizeHint> DoubleEndedIterator<(uint, A)> +for Enumerate { + #[inline] + fn next_back(&mut self) -> Option<(uint, A)> { + match self.iter.next_back() { + Some(a) => { + let (len, _) = self.iter.size_hint(); + let ret = Some((self.count + len, a)); + ret + } + _ => None + } + } +} + impl> RandomAccessIterator<(uint, A)> for Enumerate { #[inline] fn indexable(&self) -> uint { diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 12aebe20161a0..6ddb2a7228652 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -2319,6 +2319,9 @@ iterator!{impl VecIterator -> &'self T} double_ended_iterator!{impl VecIterator -> &'self T} pub type RevIterator<'self, T> = Invert>; +impl<'self, T> ExactSizeHint for VecIterator<'self, T> {} +impl<'self, T> ExactSizeHint for VecMutIterator<'self, T> {} + impl<'self, T> Clone for VecIterator<'self, T> { fn clone(&self) -> VecIterator<'self, T> { *self } } From ed607dd24aa1e041e4077b356e6bfa88c56b7fcf Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 30 Aug 2013 20:00:07 +0200 Subject: [PATCH 2/9] std::iterator: Implement .next_back() for Zip Let Zip be double-ended when both its children have the ExactSizeHint trait. --- src/libstd/iterator.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 19596421cb285..58ebb35846dac 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -936,6 +936,29 @@ impl, U: Iterator> Iterator<(A, B)> for Zip { } } +impl + ExactSizeHint, + U: DoubleEndedIterator + ExactSizeHint> DoubleEndedIterator<(A, B)> +for Zip { + #[inline] + fn next_back(&mut self) -> Option<(A, B)> { + let (a_sz, _) = self.a.size_hint(); + let (b_sz, _) = self.b.size_hint(); + if a_sz < b_sz { + for _ in range(0, b_sz - a_sz) { self.b.next_back(); } + } else if a_sz > b_sz { + for _ in range(0, a_sz - b_sz) { self.a.next_back(); } + } + let (a_sz, _) = self.a.size_hint(); + let (b_sz, _) = self.b.size_hint(); + assert!(a_sz == b_sz); + match (self.a.next_back(), self.b.next_back()) { + (Some(x), Some(y)) => Some((x, y)), + _ => None + } + } +} + impl, U: RandomAccessIterator> RandomAccessIterator<(A, B)> for Zip { #[inline] From e7955b2a7d880ecf2de30e5bc3a452bea0db4fd4 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 30 Aug 2013 20:00:11 +0200 Subject: [PATCH 3/9] std::iterator: Add tests for .next_back() on Zip and Enumerate --- src/libstd/iterator.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 58ebb35846dac..e2ac9f0339575 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -2273,6 +2273,33 @@ mod tests { assert_eq!(it.next(), None); } + #[test] + fn test_double_ended_enumerate() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut it = xs.iter().map(|&x| x).enumerate(); + assert_eq!(it.next(), Some((0, 1))); + assert_eq!(it.next(), Some((1, 2))); + assert_eq!(it.next_back(), Some((5, 6))); + assert_eq!(it.next_back(), Some((4, 5))); + assert_eq!(it.next_back(), Some((3, 4))); + assert_eq!(it.next_back(), Some((2, 3))); + assert_eq!(it.next(), None); + } + + #[test] + fn test_double_ended_zip() { + let xs = [1, 2, 3, 4, 5, 6]; + let ys = [1, 2, 3, 7]; + let a = xs.iter().map(|&x| x); + let b = ys.iter().map(|&x| x); + let mut it = a.zip(b); + assert_eq!(it.next(), Some((1, 1))); + assert_eq!(it.next(), Some((2, 2))); + assert_eq!(it.next_back(), Some((4, 7))); + assert_eq!(it.next_back(), Some((3, 3))); + assert_eq!(it.next(), None); + } + #[test] fn test_double_ended_filter() { let xs = [1, 2, 3, 4, 5, 6]; From db22f2627d625ba9481a16e44f1cc3195e8d6ef7 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 30 Aug 2013 20:00:14 +0200 Subject: [PATCH 4/9] std: Implement .rposition() on double-ended iterators with known size This is a generalization of the vector .rposition() method, to all double-ended iterators that have the ExactSizeHint trait. This resolves the slight asymmetry around `position` and `rposition` * position from front is `vec.iter().position()` * position from the back was, `vec.rposition()` is now `vec.iter().rposition()` Additionally, other indexed sequences (only `extra::ringbuf` I think), will have the same method available once it implements ExactSizeHint. --- src/libextra/num/bigint.rs | 2 +- src/libstd/iterator.rs | 33 ++++++++++++++++++++++++++++++++- src/libstd/prelude.rs | 2 +- src/libstd/vec.rs | 38 ++++---------------------------------- 4 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 5fd9690d9b0b3..cb76422815530 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -525,7 +525,7 @@ impl BigUint { #[inline] pub fn new(v: ~[BigDigit]) -> BigUint { // omit trailing zeros - let new_len = v.rposition(|n| *n != 0).map_move_default(0, |p| p + 1); + let new_len = v.iter().rposition(|n| *n != 0).map_move_default(0, |p| p + 1); if new_len == v.len() { return BigUint { data: v }; } let mut v = v; diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index e2ac9f0339575..d1b59c3097862 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -18,7 +18,7 @@ implementing the `Iterator` trait. */ use cmp; -use num::{Zero, One, Integer, CheckedAdd, Saturating}; +use num::{Zero, One, Integer, CheckedAdd, CheckedSub, Saturating}; use option::{Option, Some, None}; use ops::{Add, Mul, Sub}; use cmp::Ord; @@ -604,6 +604,37 @@ impl<'self, A, T: DoubleEndedIterator<&'self mut A>> MutableDoubleEndedIterator } } +/// A double-ended iterator with known size +pub trait ExactSizeDoubleEndedIterator { + /// Return the index of the last element satisfying the specified predicate + /// + /// If no element matches, None is returned. + #[inline] + fn rposition(&mut self, predicate: &fn(A) -> bool) -> Option; +} + +impl + ExactSizeHint> ExactSizeDoubleEndedIterator for T { + fn rposition(&mut self, predicate: &fn(A) -> bool) -> Option { + let (size, _) = self.size_hint(); + let mut i = size; + loop { + match self.next_back() { + None => break, + Some(x) => { + i = match i.checked_sub(&1) { + Some(x) => x, + None => fail!("rposition: incorrect ExactSizeHint") + }; + if predicate(x) { + return Some(i) + } + } + } + } + None + } +} + /// An object implementing random access indexing by `uint` /// /// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`. diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 24b3dc20260b1..e8eb6d871ee67 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -52,7 +52,7 @@ pub use hash::Hash; pub use num::Times; pub use iterator::{FromIterator, Extendable}; pub use iterator::{Iterator, DoubleEndedIterator, RandomAccessIterator, ClonableIterator}; -pub use iterator::{OrdIterator, MutableDoubleEndedIterator}; +pub use iterator::{OrdIterator, MutableDoubleEndedIterator, ExactSizeDoubleEndedIterator}; pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; pub use num::{Orderable, Signed, Unsigned, Round}; pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic}; diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 6ddb2a7228652..39560bd47e61a 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -274,7 +274,7 @@ impl<'self, T> Iterator<&'self [T]> for RSplitIterator<'self, T> { return Some(self.v); } - match self.v.rposition(|x| (self.pred)(x)) { + match self.v.iter().rposition(|x| (self.pred)(x)) { None => { self.finished = true; Some(self.v) @@ -832,7 +832,6 @@ pub trait ImmutableVector<'self, T> { fn initn(&self, n: uint) -> &'self [T]; fn last(&self) -> &'self T; fn last_opt(&self) -> Option<&'self T>; - fn rposition(&self, f: &fn(t: &T) -> bool) -> Option; fn flat_map(&self, f: &fn(t: &T) -> ~[U]) -> ~[U]; unsafe fn unsafe_ref(&self, index: uint) -> *T; @@ -1048,21 +1047,6 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { if self.len() == 0 { None } else { Some(&self[self.len() - 1]) } } - /** - * Find the last index matching some predicate - * - * Apply function `f` to each element of `v` in reverse order. When - * function `f` returns true then an option containing the index is - * returned. If `f` matches no elements then None is returned. - */ - #[inline] - fn rposition(&self, f: &fn(t: &T) -> bool) -> Option { - for (i, t) in self.rev_iter().enumerate() { - if f(t) { return Some(self.len() - i - 1); } - } - None - } - /** * Apply a function to each element of a vector and return a concatenation * of each result vector @@ -1145,7 +1129,7 @@ impl<'self,T:Eq> ImmutableEqVector for &'self [T] { /// Find the last index containing a matching value #[inline] fn rposition_elem(&self, t: &T) -> Option { - self.rposition(|x| *x == *t) + self.iter().rposition(|x| *x == *t) } /// Return true if a vector contains an element with the given value @@ -2932,8 +2916,8 @@ mod tests { fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - assert_eq!(v.rposition(f), Some(3u)); - assert!(v.rposition(g).is_none()); + assert_eq!(v.iter().rposition(f), Some(3u)); + assert!(v.iter().rposition(g).is_none()); } #[test] @@ -3215,20 +3199,6 @@ mod tests { }; } - #[test] - #[should_fail] - fn test_rposition_fail() { - let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; - let mut i = 0; - do v.rposition |_elt| { - if i == 2 { - fail!() - } - i += 1; - false - }; - } - #[test] #[should_fail] fn test_permute_fail() { From 46a6dbc5418ce7858eeafd2b0e252d7b66049519 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 30 Aug 2013 20:00:17 +0200 Subject: [PATCH 5/9] std::str: Use reverse enumerate and .rposition Simplify code by using the reversibility of enumerate and use .rposition(). --- src/libstd/str.rs | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 3265c470e904f..0360d4ac72f6b 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -24,7 +24,7 @@ use container::{Container, Mutable}; use num::Times; use iterator::{Iterator, FromIterator, Extendable}; use iterator::{Filter, AdditiveIterator, Map}; -use iterator::{Invert, DoubleEndedIterator}; +use iterator::{Invert, DoubleEndedIterator, ExactSizeDoubleEndedIterator}; use libc; use num::{Saturating}; use option::{None, Option, Some}; @@ -484,9 +484,8 @@ for CharSplitIterator<'self, Sep> { let mut next_split = None; if self.only_ascii { - for (j, byte) in self.string.byte_rev_iter().enumerate() { + for (idx, byte) in self.string.byte_iter().enumerate().invert() { if self.sep.matches(byte as char) && byte < 128u8 { - let idx = len - j - 1; next_split = Some((idx, idx + 1)); break; } @@ -2008,16 +2007,13 @@ impl<'self> StrSlice<'self> for &'self str { /// or `None` if there is no match fn find(&self, search: C) -> Option { if search.only_ascii() { - for (i, b) in self.byte_iter().enumerate() { - if search.matches(b as char) { return Some(i) } - } + self.byte_iter().position(|b| search.matches(b as char)) } else { for (index, c) in self.char_offset_iter() { if search.matches(c) { return Some(index); } } + None } - - None } /// Returns the byte index of the last character of `self` that matches `search` @@ -2028,18 +2024,13 @@ impl<'self> StrSlice<'self> for &'self str { /// or `None` if there is no match fn rfind(&self, search: C) -> Option { if search.only_ascii() { - let mut index = self.len(); - for b in self.byte_rev_iter() { - index -= 1; - if search.matches(b as char) { return Some(index); } - } + self.byte_iter().rposition(|b| search.matches(b as char)) } else { for (index, c) in self.char_offset_rev_iter() { if search.matches(c) { return Some(index); } } + None } - - None } /// Returns the byte index of the first matching substring From 43ef5ad18410da5f50efc78fbb781f4e1037b02a Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 30 Aug 2013 20:00:26 +0200 Subject: [PATCH 6/9] std::select: Use correct indices from the front Caught a bug where .enumerate() was used on a reverse iterator. The indices should be counted from the front here (bblum confirms). --- src/libstd/select.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/select.rs b/src/libstd/select.rs index d0afeb4be8561..9f4fd8db78847 100644 --- a/src/libstd/select.rs +++ b/src/libstd/select.rs @@ -11,7 +11,7 @@ use cell::Cell; use comm; use container::Container; -use iterator::Iterator; +use iterator::{Iterator, DoubleEndedIterator}; use option::*; // use either::{Either, Left, Right}; // use rt::kill::BlockedTask; @@ -87,7 +87,7 @@ pub fn select(ports: &mut [A]) -> uint { // Task resumes. Now unblock ourselves from all the ports we blocked on. // If the success index wasn't reset, 'take' will just take all of them. // Iterate in reverse so the 'earliest' index that's ready gets returned. - for (index, port) in ports.mut_slice(0, ready_index).mut_rev_iter().enumerate() { + for (index, port) in ports.mut_slice(0, ready_index).mut_iter().enumerate().invert() { if port.unblock_from() { ready_index = index; } From 04845f0aebd6928bb924147fd93de8dac13ff850 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Sun, 1 Sep 2013 16:43:47 +0200 Subject: [PATCH 7/9] std::iterator: Add back .rposition() test --- src/libstd/iterator.rs | 25 +++++++++++++++++++++++++ src/libstd/vec.rs | 10 ---------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index d1b59c3097862..77e51e01c0ce3 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -2367,6 +2367,31 @@ mod tests { assert_eq!(it.next_back(), None) } + #[test] + fn test_rposition() { + fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } + fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } + let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; + + assert_eq!(v.iter().rposition(f), Some(3u)); + assert!(v.iter().rposition(g).is_none()); + } + + #[test] + #[should_fail] + fn test_rposition_fail() { + let v = [(~0, @0), (~0, @0), (~0, @0), (~0, @0)]; + let mut i = 0; + do v.iter().rposition |_elt| { + if i == 2 { + fail!() + } + i += 1; + false + }; + } + + #[cfg(test)] fn check_randacc_iter>(a: T, len: uint) { diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 39560bd47e61a..f8aaf653645fa 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -2910,16 +2910,6 @@ mod tests { assert!(v1.position_elem(&4).is_none()); } - #[test] - fn test_rposition() { - fn f(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'b' } - fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' } - let v = ~[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')]; - - assert_eq!(v.iter().rposition(f), Some(3u)); - assert!(v.iter().rposition(g).is_none()); - } - #[test] fn test_bsearch_elem() { assert_eq!([1,2,3,4,5].bsearch_elem(&5), Some(4)); From 35040dfccc6674e8eda71b34a8cd1b4cc1b45842 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Sun, 1 Sep 2013 16:46:12 +0200 Subject: [PATCH 8/9] std::iterator: Use ExactSize, inheriting DoubleEndedIterator Address discussion with acrichto; inherit DoubleEndedIterator so that `.rposition()` can be a default method, and that the nische of the trait is clear. Use assertions when using `.size_hint()` in reverse enumerate and `.rposition()` --- src/libstd/iterator.rs | 87 +++++++++++++++++++----------------------- src/libstd/prelude.rs | 2 +- src/libstd/str.rs | 2 +- src/libstd/vec.rs | 4 +- 4 files changed, 43 insertions(+), 52 deletions(-) diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 77e51e01c0ce3..83e07dc137981 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -604,26 +604,42 @@ impl<'self, A, T: DoubleEndedIterator<&'self mut A>> MutableDoubleEndedIterator } } -/// A double-ended iterator with known size -pub trait ExactSizeDoubleEndedIterator { + +/// An object implementing random access indexing by `uint` +/// +/// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`. +pub trait RandomAccessIterator: Iterator { + /// Return the number of indexable elements. At most `std::uint::max_value` + /// elements are indexable, even if the iterator represents a longer range. + fn indexable(&self) -> uint; + + /// Return an element at an index + fn idx(&self, index: uint) -> Option; +} + +/// An iterator that knows its exact length +/// +/// This trait is a helper for iterators like the vector iterator, so that +/// it can support double-ended enumeration. +/// +/// `Iterator::size_hint` *must* return the exact size of the iterator. +/// Note that the size must fit in `uint`. +pub trait ExactSize : DoubleEndedIterator { /// Return the index of the last element satisfying the specified predicate /// /// If no element matches, None is returned. #[inline] - fn rposition(&mut self, predicate: &fn(A) -> bool) -> Option; -} - -impl + ExactSizeHint> ExactSizeDoubleEndedIterator for T { fn rposition(&mut self, predicate: &fn(A) -> bool) -> Option { - let (size, _) = self.size_hint(); - let mut i = size; + let (lower, upper) = self.size_hint(); + assert!(upper == Some(lower)); + let mut i = lower; loop { match self.next_back() { None => break, Some(x) => { i = match i.checked_sub(&1) { Some(x) => x, - None => fail!("rposition: incorrect ExactSizeHint") + None => fail!("rposition: incorrect ExactSize") }; if predicate(x) { return Some(i) @@ -635,37 +651,13 @@ impl + ExactSizeHint> ExactSizeDoubleEndedIterator< } } -/// An object implementing random access indexing by `uint` -/// -/// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`. -pub trait RandomAccessIterator: Iterator { - /// Return the number of indexable elements. At most `std::uint::max_value` - /// elements are indexable, even if the iterator represents a longer range. - fn indexable(&self) -> uint; - - /// Return an element at an index - fn idx(&self, index: uint) -> Option; -} - -/// An iterator that knows its exact length -/// -/// This trait is a helper for iterators like the vector iterator, so that -/// it can support double-ended enumeration. -/// -/// `Iterator::size_hint` *must* return the exact size of the iterator. -/// Note that the size must fit in `uint`. -pub trait ExactSizeHint {} - // All adaptors that preserve the size of the wrapped iterator are fine // Adaptors that may overflow in `size_hint` are not, i.e. `Chain`. -impl ExactSizeHint for Enumerate {} -impl<'self, A, T: ExactSizeHint> ExactSizeHint for Inspect<'self, A, T> {} -impl ExactSizeHint for Invert {} -impl<'self, A, B, T: ExactSizeHint> ExactSizeHint for Map<'self, A, B, T> {} -impl ExactSizeHint for Peekable {} -impl ExactSizeHint for Skip {} -impl ExactSizeHint for Take {} -impl ExactSizeHint for Zip {} +impl> ExactSize<(uint, A)> for Enumerate {} +impl<'self, A, T: ExactSize> ExactSize for Inspect<'self, A, T> {} +impl> ExactSize for Invert {} +impl<'self, A, B, T: ExactSize> ExactSize for Map<'self, A, B, T> {} +impl, U: ExactSize> ExactSize<(A, B)> for Zip {} /// An double-ended iterator with the direction inverted #[deriving(Clone)] @@ -967,14 +959,14 @@ impl, U: Iterator> Iterator<(A, B)> for Zip { } } -impl + ExactSizeHint, - U: DoubleEndedIterator + ExactSizeHint> DoubleEndedIterator<(A, B)> +impl, U: ExactSize> DoubleEndedIterator<(A, B)> for Zip { #[inline] fn next_back(&mut self) -> Option<(A, B)> { - let (a_sz, _) = self.a.size_hint(); - let (b_sz, _) = self.b.size_hint(); + let (a_sz, a_upper) = self.a.size_hint(); + let (b_sz, b_upper) = self.b.size_hint(); + assert!(a_upper == Some(a_sz)); + assert!(b_upper == Some(b_sz)); if a_sz < b_sz { for _ in range(0, b_sz - a_sz) { self.b.next_back(); } } else if a_sz > b_sz { @@ -1168,15 +1160,14 @@ impl> Iterator<(uint, A)> for Enumerate { } } -impl + ExactSizeHint> DoubleEndedIterator<(uint, A)> -for Enumerate { +impl> DoubleEndedIterator<(uint, A)> for Enumerate { #[inline] fn next_back(&mut self) -> Option<(uint, A)> { match self.iter.next_back() { Some(a) => { - let (len, _) = self.iter.size_hint(); - let ret = Some((self.count + len, a)); - ret + let (lower, upper) = self.iter.size_hint(); + assert!(upper == Some(lower)); + Some((self.count + lower, a)) } _ => None } diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index e8eb6d871ee67..8f202ee85312f 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -52,7 +52,7 @@ pub use hash::Hash; pub use num::Times; pub use iterator::{FromIterator, Extendable}; pub use iterator::{Iterator, DoubleEndedIterator, RandomAccessIterator, ClonableIterator}; -pub use iterator::{OrdIterator, MutableDoubleEndedIterator, ExactSizeDoubleEndedIterator}; +pub use iterator::{OrdIterator, MutableDoubleEndedIterator, ExactSize}; pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; pub use num::{Orderable, Signed, Unsigned, Round}; pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic}; diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 0360d4ac72f6b..d1afbaf5699f7 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -24,7 +24,7 @@ use container::{Container, Mutable}; use num::Times; use iterator::{Iterator, FromIterator, Extendable}; use iterator::{Filter, AdditiveIterator, Map}; -use iterator::{Invert, DoubleEndedIterator, ExactSizeDoubleEndedIterator}; +use iterator::{Invert, DoubleEndedIterator, ExactSize}; use libc; use num::{Saturating}; use option::{None, Option, Some}; diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index f8aaf653645fa..769f2651bacbf 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -2303,8 +2303,8 @@ iterator!{impl VecIterator -> &'self T} double_ended_iterator!{impl VecIterator -> &'self T} pub type RevIterator<'self, T> = Invert>; -impl<'self, T> ExactSizeHint for VecIterator<'self, T> {} -impl<'self, T> ExactSizeHint for VecMutIterator<'self, T> {} +impl<'self, T> ExactSize<&'self T> for VecIterator<'self, T> {} +impl<'self, T> ExactSize<&'self mut T> for VecMutIterator<'self, T> {} impl<'self, T> Clone for VecIterator<'self, T> { fn clone(&self) -> VecIterator<'self, T> { *self } From 7c369ee7337cee50f8ef05b9d2833e2aa30d802e Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Sun, 1 Sep 2013 18:20:24 +0200 Subject: [PATCH 9/9] std/extra: Add ExactSize for Bitv, DList, RingBuf, Option iterators --- src/libextra/bitv.rs | 2 ++ src/libextra/dlist.rs | 3 +++ src/libextra/ringbuf.rs | 4 ++++ src/libstd/option.rs | 4 +++- 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index 63d62bd480980..03588d984d916 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -608,6 +608,8 @@ impl<'self> DoubleEndedIterator for BitvIterator<'self> { } } +impl<'self> ExactSize for BitvIterator<'self> {} + impl<'self> RandomAccessIterator for BitvIterator<'self> { #[inline] fn indexable(&self) -> uint { diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index 8e64107363785..075a0fa777704 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -472,6 +472,8 @@ impl<'self, A> DoubleEndedIterator<&'self A> for DListIterator<'self, A> { } } +impl<'self, A> ExactSize<&'self A> for DListIterator<'self, A> {} + impl<'self, A> Iterator<&'self mut A> for MutDListIterator<'self, A> { #[inline] fn next(&mut self) -> Option<&'self mut A> { @@ -508,6 +510,7 @@ impl<'self, A> DoubleEndedIterator<&'self mut A> for MutDListIterator<'self, A> } } +impl<'self, A> ExactSize<&'self mut A> for MutDListIterator<'self, A> {} /// Allow mutating the DList while iterating pub trait ListInsertion { diff --git a/src/libextra/ringbuf.rs b/src/libextra/ringbuf.rs index 4f2755374af02..9ae9b47e2076e 100644 --- a/src/libextra/ringbuf.rs +++ b/src/libextra/ringbuf.rs @@ -243,6 +243,8 @@ pub struct RingBufIterator<'self, T> { iterator!{impl RingBufIterator -> &'self T, get_ref} iterator_rev!{impl RingBufIterator -> &'self T, get_ref} +impl<'self, T> ExactSize<&'self T> for RingBufIterator<'self, T> {} + impl<'self, T> RandomAccessIterator<&'self T> for RingBufIterator<'self, T> { #[inline] fn indexable(&self) -> uint { self.rindex - self.index } @@ -268,6 +270,8 @@ pub struct RingBufMutIterator<'self, T> { iterator!{impl RingBufMutIterator -> &'self mut T, get_mut_ref} iterator_rev!{impl RingBufMutIterator -> &'self mut T, get_mut_ref} +impl<'self, T> ExactSize<&'self mut T> for RingBufMutIterator<'self, T> {} + /// Grow is only called on full elts, so nelts is also len(elts), unlike /// elsewhere. fn grow(nelts: uint, loptr: &mut uint, elts: &mut ~[Option]) { diff --git a/src/libstd/option.rs b/src/libstd/option.rs index f99a595f2eb86..dd66630187db9 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -46,7 +46,7 @@ use cmp::{Eq,Ord}; use util; use num::Zero; use iterator; -use iterator::{Iterator, DoubleEndedIterator}; +use iterator::{Iterator, DoubleEndedIterator, ExactSize}; use str::{StrSlice, OwnedStr}; use to_str::ToStr; use clone::DeepClone; @@ -402,6 +402,8 @@ impl DoubleEndedIterator for OptionIterator { } } +impl ExactSize for OptionIterator {} + #[cfg(test)] mod tests { use super::*;