Skip to content

Commit eaf4a6c

Browse files
committed
Optimize iterator adapters.
Specifically, make count, nth, and last call the corresponding methods on the underlying iterator where possible. This way, if the underlying iterator has an optimized count, nth, or last implementations (e.g. slice::Iter), these methods will propagate these optimizations. Additionally, change Skip::next to take advantage of a potentially optimized nth method on the underlying iterator.
1 parent 1320c29 commit eaf4a6c

File tree

1 file changed

+139
-18
lines changed

1 file changed

+139
-18
lines changed

src/libcore/iter.rs

Lines changed: 139 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,32 @@ impl<A, B> Iterator for Chain<A, B> where
14771477
}
14781478
}
14791479

1480+
#[inline]
1481+
fn count(self) -> usize {
1482+
(if !self.flag { self.a.count() } else { 0 }) + self.b.count()
1483+
}
1484+
1485+
#[inline]
1486+
fn nth(&mut self, mut n: usize) -> Option<A::Item> {
1487+
if !self.flag {
1488+
for x in self.a.by_ref() {
1489+
if n == 0 {
1490+
return Some(x)
1491+
}
1492+
n -= 1;
1493+
}
1494+
self.flag = true;
1495+
}
1496+
self.b.nth(n)
1497+
}
1498+
1499+
#[inline]
1500+
fn last(self) -> Option<A::Item> {
1501+
let a_last = if self.flag { None } else { self.a.last() };
1502+
let b_last = self.b.last();
1503+
b_last.or(a_last)
1504+
}
1505+
14801506
#[inline]
14811507
fn size_hint(&self) -> (usize, Option<usize>) {
14821508
let (a_lower, a_upper) = self.a.size_hint();
@@ -1782,6 +1808,20 @@ impl<I> Iterator for Enumerate<I> where I: Iterator {
17821808
fn size_hint(&self) -> (usize, Option<usize>) {
17831809
self.iter.size_hint()
17841810
}
1811+
1812+
#[inline]
1813+
fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> {
1814+
self.iter.nth(n).map(|a| {
1815+
let i = self.count + n;
1816+
self.count = i + 1;
1817+
(i, a)
1818+
})
1819+
}
1820+
1821+
#[inline]
1822+
fn count(self) -> usize {
1823+
self.iter.count()
1824+
}
17851825
}
17861826

17871827
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1839,6 +1879,28 @@ impl<I: Iterator> Iterator for Peekable<I> {
18391879
}
18401880
}
18411881

1882+
#[inline]
1883+
fn count(self) -> usize {
1884+
(if self.peeked.is_some() { 1 } else { 0 }) + self.iter.count()
1885+
}
1886+
1887+
#[inline]
1888+
fn nth(&mut self, n: usize) -> Option<I::Item> {
1889+
match self.peeked {
1890+
Some(_) if n == 0 => self.peeked.take(),
1891+
Some(_) => {
1892+
self.peeked = None;
1893+
self.iter.nth(n-1)
1894+
},
1895+
None => self.iter.nth(n)
1896+
}
1897+
}
1898+
1899+
#[inline]
1900+
fn last(self) -> Option<I::Item> {
1901+
self.iter.last().or(self.peeked)
1902+
}
1903+
18421904
#[inline]
18431905
fn size_hint(&self) -> (usize, Option<usize>) {
18441906
let (lo, hi) = self.iter.size_hint();
@@ -1965,27 +2027,46 @@ impl<I> Iterator for Skip<I> where I: Iterator {
19652027
type Item = <I as Iterator>::Item;
19662028

19672029
#[inline]
1968-
fn next(&mut self) -> Option<<I as Iterator>::Item> {
1969-
let mut next = self.iter.next();
2030+
fn next(&mut self) -> Option<I::Item> {
19702031
if self.n == 0 {
1971-
next
2032+
self.iter.next()
19722033
} else {
1973-
let mut n = self.n;
1974-
while n > 0 {
1975-
n -= 1;
1976-
match next {
1977-
Some(_) => {
1978-
next = self.iter.next();
1979-
continue
1980-
}
1981-
None => {
1982-
self.n = 0;
1983-
return None
1984-
}
1985-
}
1986-
}
2034+
let old_n = self.n;
19872035
self.n = 0;
1988-
next
2036+
self.iter.nth(old_n)
2037+
}
2038+
}
2039+
2040+
#[inline]
2041+
fn nth(&mut self, n: usize) -> Option<I::Item> {
2042+
if self.n == 0 {
2043+
self.iter.nth(n)
2044+
} else if n == 0 {
2045+
self.next()
2046+
} else {
2047+
self.next();
2048+
// Recurse on the first case.
2049+
self.iter.nth(n-1)
2050+
}
2051+
}
2052+
2053+
#[inline]
2054+
fn count(self) -> usize {
2055+
self.iter.count().saturating_sub(self.n)
2056+
}
2057+
2058+
#[inline]
2059+
fn last(mut self) -> Option<I::Item> {
2060+
if self.n == 0 {
2061+
self.iter.last()
2062+
} else {
2063+
let next = self.next();
2064+
if next.is_some() {
2065+
// recurse. n should be 0.
2066+
self.last().or(next)
2067+
} else {
2068+
None
2069+
}
19892070
}
19902071
}
19912072

@@ -2043,6 +2124,17 @@ impl<I> Iterator for Take<I> where I: Iterator{
20432124
}
20442125
}
20452126

2127+
#[inline]
2128+
fn nth(&mut self, n: usize) -> Option<I::Item> {
2129+
if self.n == 0 {
2130+
None
2131+
} else {
2132+
let n = cmp::min(self.n-1, n);
2133+
self.n -= n + 1;
2134+
self.iter.nth(n)
2135+
}
2136+
}
2137+
20462138
#[inline]
20472139
fn size_hint(&self) -> (usize, Option<usize>) {
20482140
let (lower, upper) = self.iter.size_hint();
@@ -2204,6 +2296,35 @@ impl<I> Iterator for Fuse<I> where I: Iterator {
22042296
}
22052297
}
22062298

2299+
#[inline]
2300+
fn nth(&mut self, n: usize) -> Option<I::Item> {
2301+
if self.done {
2302+
None
2303+
} else {
2304+
let nth = self.iter.nth(n);
2305+
self.done = nth.is_none();
2306+
nth
2307+
}
2308+
}
2309+
2310+
#[inline]
2311+
fn last(self) -> Option<I::Item> {
2312+
if self.done {
2313+
None
2314+
} else {
2315+
self.iter.last()
2316+
}
2317+
}
2318+
2319+
#[inline]
2320+
fn count(self) -> usize {
2321+
if self.done {
2322+
0
2323+
} else {
2324+
self.iter.count()
2325+
}
2326+
}
2327+
22072328
#[inline]
22082329
fn size_hint(&self) -> (usize, Option<usize>) {
22092330
if self.done {

0 commit comments

Comments
 (0)