Skip to content

Commit fd5f8d9

Browse files
committed
iterator: add DoubleEndedIterator concept
This implements the trait for vector iterators, replacing the reverse iterator types. The methods will stay, for implementing the future reverse Iterable traits and convenience. This can also be trivially implemented for circular buffers and other variants of arrays like strings and `SmallIntMap`/`SmallIntSet`. The `DoubleEndedIterator` trait will allow for implementing algorithms like in-place reverse on generic mutable iterators. The naming (`Range` vs. `Iterator`, `Bidirectional` vs. `DoubleEnded`) can be bikeshedded in the future.
1 parent 90db862 commit fd5f8d9

File tree

2 files changed

+85
-41
lines changed

2 files changed

+85
-41
lines changed

src/libstd/iterator.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,49 @@ pub trait Iterator<A> {
4747
fn size_hint(&self) -> (uint, Option<uint>) { (0, None) }
4848
}
4949

50+
/// A range iterator able to yield elements from both ends
51+
pub trait DoubleEndedIterator<A>: Iterator<A> {
52+
/// Yield an element from the end of the range, returning `None` if the range is empty.
53+
fn next_back(&mut self) -> Option<A>;
54+
}
55+
56+
/// Iterator adaptors provided for every `DoubleEndedIterator` implementation.
57+
///
58+
/// In the future these will be default methods instead of a utility trait.
59+
pub trait DoubleEndedIteratorUtil<A> {
60+
/// Flip the direction of the iterator
61+
fn invert(self) -> InvertIterator<A, Self>;
62+
}
63+
64+
/// Iterator adaptors provided for every `DoubleEndedIterator` implementation.
65+
///
66+
/// In the future these will be default methods instead of a utility trait.
67+
impl<A, T: DoubleEndedIterator<A>> DoubleEndedIteratorUtil<A> for T {
68+
/// Flip the direction of the iterator
69+
#[inline]
70+
fn invert(self) -> InvertIterator<A, T> {
71+
InvertIterator{iter: self}
72+
}
73+
}
74+
75+
/// An double-ended iterator with the direction inverted
76+
// FIXME #6967: Dummy A parameter to get around type inference bug
77+
pub struct InvertIterator<A, T> {
78+
priv iter: T
79+
}
80+
81+
impl<A, T: DoubleEndedIterator<A>> Iterator<A> for InvertIterator<A, T> {
82+
#[inline]
83+
fn next(&mut self) -> Option<A> { self.iter.next_back() }
84+
#[inline]
85+
fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
86+
}
87+
88+
impl<A, T: Iterator<A>> DoubleEndedIterator<A> for InvertIterator<A, T> {
89+
#[inline]
90+
fn next_back(&mut self) -> Option<A> { self.iter.next() }
91+
}
92+
5093
/// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also
5194
/// implementations of the `Iterator` trait.
5295
///
@@ -1474,4 +1517,13 @@ mod tests {
14741517
let xs = [-3, 0, 1, 5, -10];
14751518
assert_eq!(*xs.iter().min_by(|x| x.abs()).unwrap(), 0);
14761519
}
1520+
1521+
#[test]
1522+
fn test_invert() {
1523+
let xs = [2, 4, 6, 8, 10, 12, 14, 16];
1524+
let mut it = xs.iter();
1525+
it.next();
1526+
it.next();
1527+
assert_eq!(it.invert().transform(|&x| x).collect::<~[int]>(), ~[16, 14, 12, 10, 8, 6]);
1528+
}
14771529
}

src/libstd/vec.rs

Lines changed: 33 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use container::{Container, Mutable};
1818
use cmp;
1919
use cmp::{Eq, TotalEq, TotalOrd, Ordering, Less, Equal, Greater};
2020
use clone::Clone;
21-
use iterator::{FromIterator, Iterator, IteratorUtil};
21+
use iterator::*;
2222
use kinds::Copy;
2323
use libc::c_void;
2424
use num::Zero;
@@ -760,12 +760,7 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
760760
}
761761
#[inline]
762762
fn rev_iter(self) -> VecRevIterator<'self, T> {
763-
unsafe {
764-
let p = vec::raw::to_ptr(self);
765-
VecRevIterator{ptr: p.offset(self.len() - 1),
766-
end: p.offset(-1),
767-
lifetime: cast::transmute(p)}
768-
}
763+
self.iter().invert()
769764
}
770765

771766
/// Returns an iterator over the subslices of the vector which are
@@ -1717,13 +1712,9 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] {
17171712
}
17181713
}
17191714

1715+
#[inline]
17201716
fn mut_rev_iter(self) -> VecMutRevIterator<'self, T> {
1721-
unsafe {
1722-
let p = vec::raw::to_mut_ptr(self);
1723-
VecMutRevIterator{ptr: p.offset(self.len() - 1),
1724-
end: p.offset(-1),
1725-
lifetime: cast::transmute(p)}
1726-
}
1717+
self.mut_iter().invert()
17271718
}
17281719

17291720
/**
@@ -2083,53 +2074,61 @@ macro_rules! iterator {
20832074
priv lifetime: $elem // FIXME: #5922
20842075
}
20852076
};*/
2086-
(impl $name:ident -> $elem:ty, $step:expr) => {
2087-
// could be implemented with &[T] with .slice(), but this avoids bounds checks
2077+
(impl $name:ident -> $elem:ty) => {
20882078
impl<'self, T> Iterator<$elem> for $name<'self, T> {
20892079
#[inline]
20902080
fn next(&mut self) -> Option<$elem> {
2081+
// could be implemented with slices, but this avoids bounds checks
20912082
unsafe {
20922083
if self.ptr == self.end {
20932084
None
20942085
} else {
20952086
let old = self.ptr;
2096-
self.ptr = self.ptr.offset($step);
2087+
self.ptr = self.ptr.offset(1);
20972088
Some(cast::transmute(old))
20982089
}
20992090
}
21002091
}
21012092

21022093
#[inline]
21032094
fn size_hint(&self) -> (uint, Option<uint>) {
2104-
let diff = if $step > 0 {
2105-
(self.end as uint) - (self.ptr as uint)
2106-
} else {
2107-
(self.ptr as uint) - (self.end as uint)
2108-
};
2095+
let diff = (self.end as uint) - (self.ptr as uint);
21092096
let exact = diff / size_of::<$elem>();
21102097
(exact, Some(exact))
21112098
}
21122099
}
21132100
}
21142101
}
21152102

2103+
macro_rules! double_ended_iterator {
2104+
(impl $name:ident -> $elem:ty) => {
2105+
impl<'self, T> DoubleEndedIterator<$elem> for $name<'self, T> {
2106+
#[inline]
2107+
fn next_back(&mut self) -> Option<$elem> {
2108+
// could be implemented with slices, but this avoids bounds checks
2109+
unsafe {
2110+
if self.end == self.ptr {
2111+
None
2112+
} else {
2113+
self.end = self.end.offset(-1);
2114+
Some(cast::transmute(self.end))
2115+
}
2116+
}
2117+
}
2118+
}
2119+
}
2120+
}
2121+
21162122
//iterator!{struct VecIterator -> *T, &'self T}
21172123
/// An iterator for iterating over a vector.
21182124
pub struct VecIterator<'self, T> {
21192125
priv ptr: *T,
21202126
priv end: *T,
21212127
priv lifetime: &'self T // FIXME: #5922
21222128
}
2123-
iterator!{impl VecIterator -> &'self T, 1}
2124-
2125-
//iterator!{struct VecRevIterator -> *T, &'self T}
2126-
/// An iterator for iterating over a vector in reverse.
2127-
pub struct VecRevIterator<'self, T> {
2128-
priv ptr: *T,
2129-
priv end: *T,
2130-
priv lifetime: &'self T // FIXME: #5922
2131-
}
2132-
iterator!{impl VecRevIterator -> &'self T, -1}
2129+
iterator!{impl VecIterator -> &'self T}
2130+
double_ended_iterator!{impl VecIterator -> &'self T}
2131+
pub type VecRevIterator<'self, T> = InvertIterator<&'self T, VecIterator<'self, T>>;
21332132

21342133
//iterator!{struct VecMutIterator -> *mut T, &'self mut T}
21352134
/// An iterator for mutating the elements of a vector.
@@ -2138,16 +2137,9 @@ pub struct VecMutIterator<'self, T> {
21382137
priv end: *mut T,
21392138
priv lifetime: &'self mut T // FIXME: #5922
21402139
}
2141-
iterator!{impl VecMutIterator -> &'self mut T, 1}
2142-
2143-
//iterator!{struct VecMutRevIterator -> *mut T, &'self mut T}
2144-
/// An iterator for mutating the elements of a vector in reverse.
2145-
pub struct VecMutRevIterator<'self, T> {
2146-
priv ptr: *mut T,
2147-
priv end: *mut T,
2148-
priv lifetime: &'self mut T // FIXME: #5922
2149-
}
2150-
iterator!{impl VecMutRevIterator -> &'self mut T, -1}
2140+
iterator!{impl VecMutIterator -> &'self mut T}
2141+
double_ended_iterator!{impl VecMutIterator -> &'self mut T}
2142+
pub type VecMutRevIterator<'self, T> = InvertIterator<&'self mut T, VecMutIterator<'self, T>>;
21512143

21522144
/// An iterator that moves out of a vector.
21532145
pub struct VecConsumeIterator<T> {

0 commit comments

Comments
 (0)