From ce4f63dcee8997f8d2881e6e3cf9e04db085bd64 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Sat, 8 Jun 2013 12:39:52 +1000 Subject: [PATCH] std: add reverse vec iterators, replace vec::each*_reverse. --- src/libextra/num/bigint.rs | 15 +-- src/librustc/middle/trans/base.rs | 3 +- src/libstd/str.rs | 2 +- src/libstd/unstable/lang.rs | 3 +- src/libstd/vec.rs | 210 ++++++++++++++---------------- 5 files changed, 107 insertions(+), 126 deletions(-) diff --git a/src/libextra/num/bigint.rs b/src/libextra/num/bigint.rs index 77eef1d67ef..1411079d52f 100644 --- a/src/libextra/num/bigint.rs +++ b/src/libextra/num/bigint.rs @@ -19,7 +19,7 @@ A BigInt is a combination of BigUint and Sign. #[allow(missing_doc)]; use core::prelude::*; - +use core::iterator::IteratorUtil; use core::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use core::int; use core::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix, Orderable}; @@ -129,12 +129,9 @@ impl TotalOrd for BigUint { if s_len < o_len { return Less; } if s_len > o_len { return Greater; } - for self.data.eachi_reverse |i, elm| { - match (*elm, other.data[i]) { - (l, r) if l < r => return Less, - (l, r) if l > r => return Greater, - _ => loop - }; + for self.data.rev_iter().zip(other.data.rev_iter()).advance |(&self_i, &other_i)| { + cond!((self_i < other_i) { return Less; } + (self_i > other_i) { return Greater; }) } return Equal; } @@ -421,7 +418,7 @@ impl Integer for BigUint { let bn = *b.data.last(); let mut d = ~[]; let mut carry = 0; - for an.each_reverse |elt| { + for an.rev_iter().advance |elt| { let ai = BigDigit::to_uint(carry, *elt); let di = ai / (bn as uint); assert!(di < BigDigit::base); @@ -648,7 +645,7 @@ impl BigUint { let mut borrow = 0; let mut shifted = ~[]; - for self.data.each_reverse |elem| { + for self.data.rev_iter().advance |elem| { shifted = ~[(*elem >> n_bits) | borrow] + shifted; borrow = *elem << (BigDigit::bits - n_bits); } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 2d1dd34af4a..f368255030b 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -64,6 +64,7 @@ use middle::ty; use util::common::indenter; use util::ppaux::{Repr, ty_to_str}; +use core::iterator::IteratorUtil; use core::hash; use core::hashmap::{HashMap, HashSet}; use core::int; @@ -1275,7 +1276,7 @@ pub fn trans_block_cleanups_(bcx: block, bcx.ccx().sess.opts.debugging_opts & session::no_landing_pads != 0; if bcx.unreachable && !no_lpads { return bcx; } let mut bcx = bcx; - for cleanups.each_reverse |cu| { + for cleanups.rev_iter().advance |cu| { match *cu { clean(cfn, cleanup_type) | clean_temp(_, cfn, cleanup_type) => { // Some types don't need to be cleaned up during diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 359c64c5f28..8dc546ec4f8 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -3964,7 +3964,7 @@ mod tests { let s = ~"ศไทย中华Việt Nam"; let v = ~['ศ','ไ','ท','ย','中','华','V','i','ệ','t',' ','N','a','m']; let mut pos = s.len(); - for v.each_reverse |ch| { + for v.rev_iter().advance |ch| { assert!(s.char_at_reverse(pos) == *ch); pos -= from_char(*ch).len(); } diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index 350b18d4541..cd3e0cf303e 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -10,6 +10,7 @@ //! Runtime calls emitted by the compiler. +use iterator::IteratorUtil; use uint; use cast::transmute; use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int, STDERR_FILENO}; @@ -133,7 +134,7 @@ unsafe fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { Some(borrow_list) => { // recording borrows let mut msg = ~"borrowed"; let mut sep = " at "; - for borrow_list.each_reverse |entry| { + for borrow_list.rev_iter().advance |entry| { if entry.box == box { str::push_str(&mut msg, sep); let filename = str::raw::from_c_str(entry.file); diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index d8424f4a29e..f34e1a91b69 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -1598,34 +1598,6 @@ pub fn eachi<'r,T>(v: &'r [T], f: &fn(uint, v: &'r T) -> bool) -> bool { return true; } -/** - * Iterates over a vector's elements in reverse - * - * Return true to continue, false to break. - */ -#[inline(always)] -pub fn each_reverse<'r,T>(v: &'r [T], blk: &fn(v: &'r T) -> bool) -> bool { - eachi_reverse(v, |_i, v| blk(v)) -} - -/** - * Iterates over a vector's elements and indices in reverse - * - * Return true to continue, false to break. - */ -#[inline(always)] -pub fn eachi_reverse<'r,T>(v: &'r [T], - blk: &fn(i: uint, v: &'r T) -> bool) -> bool { - let mut i = v.len(); - while i > 0 { - i -= 1; - if !blk(i, &v[i]) { - return false; - } - } - return true; -} - /** * Iterate over all permutations of vector `v`. * @@ -1964,6 +1936,7 @@ impl<'self,T:Copy> CopyableVector for &'self [T] { pub trait ImmutableVector<'self, T> { fn slice(&self, start: uint, end: uint) -> &'self [T]; fn iter(self) -> VecIterator<'self, T>; + fn rev_iter(self) -> VecRevIterator<'self, T>; fn head(&self) -> &'self T; fn head_opt(&self) -> Option<&'self T>; fn tail(&self) -> &'self [T]; @@ -1974,8 +1947,6 @@ pub trait ImmutableVector<'self, T> { fn last_opt(&self) -> Option<&'self T>; fn position(&self, f: &fn(t: &T) -> bool) -> Option; fn rposition(&self, f: &fn(t: &T) -> bool) -> Option; - fn each_reverse(&self, blk: &fn(&T) -> bool) -> bool; - fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool) -> bool; fn foldr<'a, U>(&'a self, z: U, p: &fn(t: &'a T, u: U) -> U) -> U; fn map(&self, f: &fn(t: &T) -> U) -> ~[U]; fn mapi(&self, f: &fn(uint, t: &T) -> U) -> ~[U]; @@ -2002,6 +1973,15 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { lifetime: cast::transmute(p)} } } + #[inline] + fn rev_iter(self) -> VecRevIterator<'self, T> { + unsafe { + let p = vec::raw::to_ptr(self); + VecRevIterator{ptr: p.offset(self.len() - 1), + end: p.offset(-1), + lifetime: cast::transmute(p)} + } + } /// Returns the first element of a vector, failing if the vector is empty. #[inline] @@ -2059,18 +2039,6 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { rposition(*self, f) } - /// Iterates over a vector's elements in reverse. - #[inline] - fn each_reverse(&self, blk: &fn(&T) -> bool) -> bool { - each_reverse(*self, blk) - } - - /// Iterates over a vector's elements and indices in reverse. - #[inline] - fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool) -> bool { - eachi_reverse(*self, blk) - } - /// Reduce a vector from right to left #[inline] fn foldr<'a, U>(&'a self, z: U, p: &fn(t: &'a T, u: U) -> U) -> U { @@ -2350,7 +2318,8 @@ impl OwnedEqVector for ~[T] { #[allow(missing_doc)] pub trait MutableVector<'self, T> { fn mut_slice(self, start: uint, end: uint) -> &'self mut [T]; - fn mut_iter(self) -> MutVecIterator<'self, T>; + fn mut_iter(self) -> VecMutIterator<'self, T>; + fn mut_rev_iter(self) -> VecMutRevIterator<'self, T>; unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T; unsafe fn unsafe_set(&self, index: uint, val: T); @@ -2363,14 +2332,23 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { } #[inline] - fn mut_iter(self) -> MutVecIterator<'self, T> { + fn mut_iter(self) -> VecMutIterator<'self, T> { unsafe { let p = vec::raw::to_mut_ptr(self); - MutVecIterator{ptr: p, end: p.offset(self.len()), + VecMutIterator{ptr: p, end: p.offset(self.len()), lifetime: cast::transmute(p)} } } + fn mut_rev_iter(self) -> VecMutRevIterator<'self, T> { + unsafe { + let p = vec::raw::to_mut_ptr(self); + VecMutRevIterator{ptr: p.offset(self.len() - 1), + end: p.offset(-1), + lifetime: cast::transmute(p)} + } + } + #[inline(always)] unsafe fn unsafe_mut_ref(&self, index: uint) -> *mut T { let pair_ptr: &(*mut T, uint) = transmute(self); @@ -2872,52 +2850,69 @@ impl Clone for ~[A] { } } -/// An external iterator for vectors (use with the std::iterator module) +macro_rules! iterator { + /* FIXME: #4375 Cannot attach documentation/attributes to a macro generated struct. + (struct $name:ident -> $ptr:ty, $elem:ty) => { + pub struct $name<'self, T> { + priv ptr: $ptr, + priv end: $ptr, + priv lifetime: $elem // FIXME: #5922 + } + };*/ + (impl $name:ident -> $elem:ty, $step:expr) => { + // could be implemented with &[T] with .slice(), but this avoids bounds checks + impl<'self, T> Iterator<$elem> for $name<'self, T> { + #[inline] + fn next(&mut self) -> Option<$elem> { + unsafe { + if self.ptr == self.end { + None + } else { + let old = self.ptr; + self.ptr = self.ptr.offset($step); + Some(cast::transmute(old)) + } + } + } + } + } +} + +//iterator!{struct VecIterator -> *T, &'self T} +/// An iterator for iterating over a vector pub struct VecIterator<'self, T> { priv ptr: *T, priv end: *T, priv lifetime: &'self T // FIXME: #5922 } +iterator!{impl VecIterator -> &'self T, 1} -// could be implemented with &[T] with .slice(), but this avoids bounds checks -impl<'self, T> Iterator<&'self T> for VecIterator<'self, T> { - #[inline] - fn next(&mut self) -> Option<&'self T> { - unsafe { - if self.ptr == self.end { - None - } else { - let old = self.ptr; - self.ptr = self.ptr.offset(1); - Some(cast::transmute(old)) - } - } - } +//iterator!{struct VecRevIterator -> *T, &'self T} +/// An iterator for iterating over a vector in reverse +pub struct VecRevIterator<'self, T> { + priv ptr: *T, + priv end: *T, + priv lifetime: &'self T // FIXME: #5922 } +iterator!{impl VecRevIterator -> &'self T, -1} -/// An external iterator for vectors with the possibility of mutating -/// elements. (use with the std::iterator module) -pub struct MutVecIterator<'self, T> { +//iterator!{struct VecMutIterator -> *mut T, &'self mut T} +/// An iterator for mutating the elements of a vector +pub struct VecMutIterator<'self, T> { priv ptr: *mut T, priv end: *mut T, priv lifetime: &'self mut T // FIXME: #5922 } +iterator!{impl VecMutIterator -> &'self mut T, 1} -// could be implemented with &[T] with .slice(), but this avoids bounds checks -impl<'self, T> Iterator<&'self mut T> for MutVecIterator<'self, T> { - #[inline] - fn next(&mut self) -> Option<&'self mut T> { - unsafe { - if self.ptr == self.end { - None - } else { - let old = self.ptr; - self.ptr = self.ptr.offset(1); - Some(cast::transmute(old)) - } - } - } +//iterator!{struct VecMutRevIterator -> *mut T, &'self mut T} +/// An iterator for mutating the elements of a vector in reverse +pub struct VecMutRevIterator<'self, T> { + priv ptr: *mut T, + priv end: *mut T, + priv lifetime: &'self mut T // FIXME: #5922 } +iterator!{impl VecMutRevIterator -> &'self mut T, -1} impl FromIter for ~[T]{ #[inline(always)] @@ -3527,43 +3522,6 @@ mod tests { assert_eq!(i, 6); } - #[test] - fn test_each_reverse_empty() { - let v: ~[int] = ~[]; - for v.each_reverse |_v| { - fail!(); // should never execute - } - } - - #[test] - fn test_each_reverse_nonempty() { - let mut i = 0; - for each_reverse([1, 2, 3]) |v| { - if i == 0 { assert!(*v == 3); } - i += *v - } - assert_eq!(i, 6); - } - - #[test] - fn test_eachi_reverse() { - let mut i = 0; - for eachi_reverse([0, 1, 2]) |j, v| { - if i == 0 { assert!(*v == 2); } - assert_eq!(j, *v as uint); - i += *v; - } - assert_eq!(i, 3); - } - - #[test] - fn test_eachi_reverse_empty() { - let v: ~[int] = ~[]; - for v.eachi_reverse |_i, _v| { - fail!(); // should never execute - } - } - #[test] fn test_each_ret_len0() { let mut a0 : [int, .. 0] = []; @@ -4642,6 +4600,30 @@ mod tests { assert_eq!(xs, [2, 3, 4, 5, 6]) } + #[test] + fn test_rev_iterator() { + use iterator::*; + + let xs = [1, 2, 5, 10, 11]; + let ys = [11, 10, 5, 2, 1]; + let mut i = 0; + for xs.rev_iter().advance |&x| { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, 5); + } + + #[test] + fn test_mut_rev_iterator() { + use iterator::*; + let mut xs = [1, 2, 3, 4, 5]; + for xs.mut_rev_iter().enumerate().advance |(i,x)| { + *x += i; + } + assert_eq!(xs, [5, 5, 5, 5, 5]) + } + #[test] fn test_reverse_part() { let mut values = [1,2,3,4,5];