Skip to content

ExactSize: Reversible enumerate and generic rposition() #8884

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
2 changes: 2 additions & 0 deletions src/libextra/bitv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
3 changes: 3 additions & 0 deletions src/libextra/dlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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> {
Expand Down
2 changes: 1 addition & 1 deletion src/libextra/num/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions src/libextra/ringbuf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand All @@ -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>]) {
Expand Down
134 changes: 133 additions & 1 deletion src/libstd/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -604,6 +604,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`.
Expand All @@ -616,6 +617,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> {
Expand Down Expand Up @@ -916,6 +959,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]
Expand Down Expand Up @@ -1094,6 +1160,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 {
Expand Down Expand Up @@ -2215,6 +2295,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];
Expand Down Expand Up @@ -2251,6 +2358,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)
{
Expand Down
4 changes: 3 additions & 1 deletion src/libstd/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -402,6 +402,8 @@ impl<A> DoubleEndedIterator<A> for OptionIterator<A> {
}
}

impl<A> ExactSize<A> for OptionIterator<A> {}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
2 changes: 1 addition & 1 deletion src/libstd/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
4 changes: 2 additions & 2 deletions src/libstd/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
21 changes: 6 additions & 15 deletions src/libstd/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -2008,16 +2007,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`
Expand All @@ -2028,18 +2024,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
Expand Down
Loading