mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-18 06:56:59 +00:00
auto merge of #8884 : blake2-ppc/rust/exact-size-hint, r=huonw
The message of the first commit explains (edited for changed trait name): The trait `ExactSize` 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 `ExactSize` 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). --- It may seem complicated just to solve these small "niggles", (It's really the reversible enumerate case that's the most interesting) but only a few core iterators need to implement this trait. While we gain more capabilities generically for some iterators, it becomes a tad more complicated to figure out if a type has the right trait impls for it.
This commit is contained in:
commit
1ac8e8885b
@ -608,6 +608,8 @@ impl<'self> DoubleEndedIterator<bool> for BitvIterator<'self> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'self> ExactSize<bool> for BitvIterator<'self> {}
|
||||
|
||||
impl<'self> RandomAccessIterator<bool> for BitvIterator<'self> {
|
||||
#[inline]
|
||||
fn indexable(&self) -> uint {
|
||||
|
@ -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<A> {
|
||||
|
@ -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;
|
||||
|
@ -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<T>(nelts: uint, loptr: &mut uint, elts: &mut ~[Option<T>]) {
|
||||
|
@ -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;
|
||||
@ -641,6 +641,7 @@ impl<'self, A, T: DoubleEndedIterator<&'self mut A>> MutableDoubleEndedIterator
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// An object implementing random access indexing by `uint`
|
||||
///
|
||||
/// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`.
|
||||
@ -653,6 +654,48 @@ pub trait RandomAccessIterator<A>: Iterator<A> {
|
||||
fn idx(&self, index: uint) -> Option<A>;
|
||||
}
|
||||
|
||||
/// 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<A> : DoubleEndedIterator<A> {
|
||||
/// 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<uint> {
|
||||
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 ExactSize")
|
||||
};
|
||||
if predicate(x) {
|
||||
return Some(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// 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<A, T: ExactSize<A>> ExactSize<(uint, A)> for Enumerate<T> {}
|
||||
impl<'self, A, T: ExactSize<A>> ExactSize<A> for Inspect<'self, A, T> {}
|
||||
impl<A, T: ExactSize<A>> ExactSize<A> for Invert<T> {}
|
||||
impl<'self, A, B, T: ExactSize<A>> ExactSize<B> for Map<'self, A, B, T> {}
|
||||
impl<A, B, T: ExactSize<A>, U: ExactSize<B>> ExactSize<(A, B)> for Zip<T, U> {}
|
||||
|
||||
/// An double-ended iterator with the direction inverted
|
||||
#[deriving(Clone)]
|
||||
pub struct Invert<T> {
|
||||
@ -956,6 +999,29 @@ impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<(A, B)> for Zip<T, U> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, T: ExactSize<A>, U: ExactSize<B>> DoubleEndedIterator<(A, B)>
|
||||
for Zip<T, U> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<(A, B)> {
|
||||
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 {
|
||||
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<A, B, T: RandomAccessIterator<A>, U: RandomAccessIterator<B>>
|
||||
RandomAccessIterator<(A, B)> for Zip<T, U> {
|
||||
#[inline]
|
||||
@ -1137,6 +1203,20 @@ impl<A, T: Iterator<A>> Iterator<(uint, A)> for Enumerate<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, T: ExactSize<A>> DoubleEndedIterator<(uint, A)> for Enumerate<T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<(uint, A)> {
|
||||
match self.iter.next_back() {
|
||||
Some(a) => {
|
||||
let (lower, upper) = self.iter.size_hint();
|
||||
assert!(upper == Some(lower));
|
||||
Some((self.count + lower, a))
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<(uint, A)> for Enumerate<T> {
|
||||
#[inline]
|
||||
fn indexable(&self) -> uint {
|
||||
@ -2331,6 +2411,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];
|
||||
@ -2367,6 +2474,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: Eq, T: Clone + RandomAccessIterator<A>>(a: T, len: uint)
|
||||
{
|
||||
|
@ -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<A> DoubleEndedIterator<A> for OptionIterator<A> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> ExactSize<A> for OptionIterator<A> {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -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, ExactSize};
|
||||
pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
|
||||
pub use num::{Orderable, Signed, Unsigned, Round};
|
||||
pub use num::{Algebraic, Trigonometric, Exponential, Hyperbolic};
|
||||
|
@ -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<A: 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;
|
||||
}
|
||||
|
@ -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, ExactSize};
|
||||
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;
|
||||
}
|
||||
@ -2006,16 +2005,13 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
/// or `None` if there is no match
|
||||
fn find<C: CharEq>(&self, search: C) -> Option<uint> {
|
||||
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`
|
||||
@ -2026,18 +2022,13 @@ impl<'self> StrSlice<'self> for &'self str {
|
||||
/// or `None` if there is no match
|
||||
fn rfind<C: CharEq>(&self, search: C) -> Option<uint> {
|
||||
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
|
||||
|
@ -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<uint>;
|
||||
fn flat_map<U>(&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<uint> {
|
||||
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<T> for &'self [T] {
|
||||
/// Find the last index containing a matching value
|
||||
#[inline]
|
||||
fn rposition_elem(&self, t: &T) -> Option<uint> {
|
||||
self.rposition(|x| *x == *t)
|
||||
self.iter().rposition(|x| *x == *t)
|
||||
}
|
||||
|
||||
/// Return true if a vector contains an element with the given value
|
||||
@ -2319,6 +2303,9 @@ iterator!{impl VecIterator -> &'self T}
|
||||
double_ended_iterator!{impl VecIterator -> &'self T}
|
||||
pub type RevIterator<'self, T> = Invert<VecIterator<'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 }
|
||||
}
|
||||
@ -2923,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.rposition(f), Some(3u));
|
||||
assert!(v.rposition(g).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bsearch_elem() {
|
||||
assert_eq!([1,2,3,4,5].bsearch_elem(&5), Some(4));
|
||||
@ -3212,20 +3189,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() {
|
||||
|
Loading…
Reference in New Issue
Block a user