From db22f2627d625ba9481a16e44f1cc3195e8d6ef7 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 30 Aug 2013 20:00:14 +0200 Subject: [PATCH] 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 5fd9690d9b0..cb764228155 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 e2ac9f03395..d1b59c30978 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 24b3dc20260..e8eb6d871ee 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 6ddb2a72286..39560bd47e6 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() {