Skip to content

Commit bab03ce

Browse files
authored
Rollup merge of rust-lang#60130 - khuey:efficient_last, r=sfackler
Add implementations of last in terms of next_back on a bunch of DoubleEndedIterators Provided a `DoubleEndedIterator` has finite length, `Iterator::last` is equivalent to `DoubleEndedIterator::next_back`. But searching forwards through the iterator when it's unnecessary is obviously not good for performance. I ran into this on one of the collection iterators. I tried adding appropriate overloads for a bunch of the iterator adapters like filter, map, etc, but I ran into a lot of type inference failures after doing so. The other interesting case is what to do with `Repeat`. Do we consider it part of the contract that `Iterator::last` will loop forever on it? The docs do say that the iterator will be evaluated until it returns None. This is also relevant for the adapters, it's trivially easy to observe whether a `Map` adapter invoked its closure a zillion times or just once for the last element.
2 parents f59c71e + 3e86cf3 commit bab03ce

File tree

14 files changed

+159
-0
lines changed

14 files changed

+159
-0
lines changed

src/liballoc/collections/binary_heap.rs

+15
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,11 @@ impl<'a, T> Iterator for Iter<'a, T> {
992992
fn size_hint(&self) -> (usize, Option<usize>) {
993993
self.iter.size_hint()
994994
}
995+
996+
#[inline]
997+
fn last(mut self) -> Option<&'a T> {
998+
self.next_back()
999+
}
9951000
}
9961001

9971002
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1047,6 +1052,11 @@ impl<T> Iterator for IntoIter<T> {
10471052
fn size_hint(&self) -> (usize, Option<usize>) {
10481053
self.iter.size_hint()
10491054
}
1055+
1056+
#[inline]
1057+
fn last(mut self) -> Option<T> {
1058+
self.next_back()
1059+
}
10501060
}
10511061

10521062
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1093,6 +1103,11 @@ impl<T> Iterator for Drain<'_, T> {
10931103
fn size_hint(&self) -> (usize, Option<usize>) {
10941104
self.iter.size_hint()
10951105
}
1106+
1107+
#[inline]
1108+
fn last(mut self) -> Option<T> {
1109+
self.next_back()
1110+
}
10961111
}
10971112

10981113
#[stable(feature = "drain", since = "1.6.0")]

src/liballoc/collections/btree/map.rs

+40
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,11 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
11931193
fn size_hint(&self) -> (usize, Option<usize>) {
11941194
(self.length, Some(self.length))
11951195
}
1196+
1197+
#[inline]
1198+
fn last(mut self) -> Option<(&'a K, &'a V)> {
1199+
self.next_back()
1200+
}
11961201
}
11971202

11981203
#[stable(feature = "fused", since = "1.26.0")]
@@ -1253,6 +1258,11 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
12531258
fn size_hint(&self) -> (usize, Option<usize>) {
12541259
(self.length, Some(self.length))
12551260
}
1261+
1262+
#[inline]
1263+
fn last(mut self) -> Option<(&'a K, &'a mut V)> {
1264+
self.next_back()
1265+
}
12561266
}
12571267

12581268
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1359,6 +1369,11 @@ impl<K, V> Iterator for IntoIter<K, V> {
13591369
fn size_hint(&self) -> (usize, Option<usize>) {
13601370
(self.length, Some(self.length))
13611371
}
1372+
1373+
#[inline]
1374+
fn last(mut self) -> Option<(K, V)> {
1375+
self.next_back()
1376+
}
13621377
}
13631378

13641379
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1421,6 +1436,11 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> {
14211436
fn size_hint(&self) -> (usize, Option<usize>) {
14221437
self.inner.size_hint()
14231438
}
1439+
1440+
#[inline]
1441+
fn last(mut self) -> Option<&'a K> {
1442+
self.next_back()
1443+
}
14241444
}
14251445

14261446
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1458,6 +1478,11 @@ impl<'a, K, V> Iterator for Values<'a, K, V> {
14581478
fn size_hint(&self) -> (usize, Option<usize>) {
14591479
self.inner.size_hint()
14601480
}
1481+
1482+
#[inline]
1483+
fn last(mut self) -> Option<&'a V> {
1484+
self.next_back()
1485+
}
14611486
}
14621487

14631488
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1495,6 +1520,11 @@ impl<'a, K, V> Iterator for Range<'a, K, V> {
14951520
unsafe { Some(self.next_unchecked()) }
14961521
}
14971522
}
1523+
1524+
#[inline]
1525+
fn last(mut self) -> Option<(&'a K, &'a V)> {
1526+
self.next_back()
1527+
}
14981528
}
14991529

15001530
#[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -1508,6 +1538,11 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
15081538
fn size_hint(&self) -> (usize, Option<usize>) {
15091539
self.inner.size_hint()
15101540
}
1541+
1542+
#[inline]
1543+
fn last(mut self) -> Option<&'a mut V> {
1544+
self.next_back()
1545+
}
15111546
}
15121547

15131548
#[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -1626,6 +1661,11 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> {
16261661
unsafe { Some(self.next_unchecked()) }
16271662
}
16281663
}
1664+
1665+
#[inline]
1666+
fn last(mut self) -> Option<(&'a K, &'a mut V)> {
1667+
self.next_back()
1668+
}
16291669
}
16301670

16311671
impl<'a, K, V> RangeMut<'a, K, V> {

src/liballoc/collections/btree/set.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,11 @@ impl<'a, T> Iterator for Iter<'a, T> {
10191019
fn size_hint(&self) -> (usize, Option<usize>) {
10201020
self.iter.size_hint()
10211021
}
1022+
1023+
#[inline]
1024+
fn last(mut self) -> Option<&'a T> {
1025+
self.next_back()
1026+
}
10221027
}
10231028
#[stable(feature = "rust1", since = "1.0.0")]
10241029
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
@@ -1044,6 +1049,11 @@ impl<T> Iterator for IntoIter<T> {
10441049
fn size_hint(&self) -> (usize, Option<usize>) {
10451050
self.iter.size_hint()
10461051
}
1052+
1053+
#[inline]
1054+
fn last(mut self) -> Option<T> {
1055+
self.next_back()
1056+
}
10471057
}
10481058
#[stable(feature = "rust1", since = "1.0.0")]
10491059
impl<T> DoubleEndedIterator for IntoIter<T> {
@@ -1073,6 +1083,11 @@ impl<'a, T> Iterator for Range<'a, T> {
10731083
fn next(&mut self) -> Option<&'a T> {
10741084
self.iter.next().map(|(k, _)| k)
10751085
}
1086+
1087+
#[inline]
1088+
fn last(mut self) -> Option<&'a T> {
1089+
self.next_back()
1090+
}
10761091
}
10771092

10781093
#[stable(feature = "btree_range", since = "1.17.0")]

src/liballoc/string.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2377,6 +2377,10 @@ impl Iterator for Drain<'_> {
23772377
fn size_hint(&self) -> (usize, Option<usize>) {
23782378
self.iter.size_hint()
23792379
}
2380+
#[inline]
2381+
fn last(mut self) -> Option<char> {
2382+
self.next_back()
2383+
}
23802384
}
23812385

23822386
#[stable(feature = "drain", since = "1.6.0")]

src/liballoc/vec.rs

+14
Original file line numberDiff line numberDiff line change
@@ -2395,6 +2395,11 @@ impl<T> Iterator for IntoIter<T> {
23952395
fn count(self) -> usize {
23962396
self.len()
23972397
}
2398+
2399+
#[inline]
2400+
fn last(mut self) -> Option<T> {
2401+
self.next_back()
2402+
}
23982403
}
23992404

24002405
#[stable(feature = "rust1", since = "1.0.0")]
@@ -2514,6 +2519,11 @@ impl<T> Iterator for Drain<'_, T> {
25142519
fn size_hint(&self) -> (usize, Option<usize>) {
25152520
self.iter.size_hint()
25162521
}
2522+
2523+
#[inline]
2524+
fn last(mut self) -> Option<T> {
2525+
self.next_back()
2526+
}
25172527
}
25182528

25192529
#[stable(feature = "drain", since = "1.6.0")]
@@ -2583,6 +2593,10 @@ impl<I: Iterator> Iterator for Splice<'_, I> {
25832593
fn size_hint(&self) -> (usize, Option<usize>) {
25842594
self.drain.size_hint()
25852595
}
2596+
2597+
fn last(mut self) -> Option<Self::Item> {
2598+
self.next_back()
2599+
}
25862600
}
25872601

25882602
#[stable(feature = "vec_splice", since = "1.21.0")]

src/libcore/ascii.rs

+2
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ impl Iterator for EscapeDefault {
117117
type Item = u8;
118118
fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) }
119119
fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
120+
#[inline]
121+
fn last(mut self) -> Option<u8> { self.next_back() }
120122
}
121123
#[stable(feature = "rust1", since = "1.0.0")]
122124
impl DoubleEndedIterator for EscapeDefault {

src/libcore/iter/adapters/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ impl<I> Iterator for Rev<I> where I: DoubleEndedIterator {
7373
{
7474
self.iter.position(predicate)
7575
}
76+
77+
#[inline]
78+
fn last(mut self) -> Option<Self::Item> {
79+
self.next_back()
80+
}
7681
}
7782

7883
#[stable(feature = "rust1", since = "1.0.0")]

src/libcore/slice/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -3541,6 +3541,11 @@ impl<'a, T, P> Iterator for Split<'a, T, P> where P: FnMut(&T) -> bool {
35413541
(1, Some(self.v.len() + 1))
35423542
}
35433543
}
3544+
3545+
#[inline]
3546+
fn last(mut self) -> Option<Self::Item> {
3547+
self.next_back()
3548+
}
35443549
}
35453550

35463551
#[stable(feature = "rust1", since = "1.0.0")]
@@ -3639,6 +3644,11 @@ impl<'a, T, P> Iterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {
36393644
(1, Some(self.v.len() + 1))
36403645
}
36413646
}
3647+
3648+
#[inline]
3649+
fn last(mut self) -> Option<Self::Item> {
3650+
self.next_back()
3651+
}
36423652
}
36433653

36443654
#[stable(feature = "rust1", since = "1.0.0")]
@@ -3704,6 +3714,11 @@ impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
37043714
fn size_hint(&self) -> (usize, Option<usize>) {
37053715
self.inner.size_hint()
37063716
}
3717+
3718+
#[inline]
3719+
fn last(mut self) -> Option<Self::Item> {
3720+
self.next_back()
3721+
}
37073722
}
37083723

37093724
#[stable(feature = "slice_rsplit", since = "1.27.0")]
@@ -3768,6 +3783,11 @@ impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {
37683783
fn size_hint(&self) -> (usize, Option<usize>) {
37693784
self.inner.size_hint()
37703785
}
3786+
3787+
#[inline]
3788+
fn last(mut self) -> Option<Self::Item> {
3789+
self.next_back()
3790+
}
37713791
}
37723792

37733793
#[stable(feature = "slice_rsplit", since = "1.27.0")]

src/libcore/str/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -1333,6 +1333,11 @@ impl<'a> Iterator for Lines<'a> {
13331333
fn size_hint(&self) -> (usize, Option<usize>) {
13341334
self.0.size_hint()
13351335
}
1336+
1337+
#[inline]
1338+
fn last(mut self) -> Option<Self::Item> {
1339+
self.next_back()
1340+
}
13361341
}
13371342

13381343
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1379,6 +1384,11 @@ impl<'a> Iterator for LinesAny<'a> {
13791384
fn size_hint(&self) -> (usize, Option<usize>) {
13801385
self.0.size_hint()
13811386
}
1387+
1388+
#[inline]
1389+
fn last(mut self) -> Option<Self::Item> {
1390+
self.next_back()
1391+
}
13821392
}
13831393

13841394
#[stable(feature = "rust1", since = "1.0.0")]
@@ -4217,6 +4227,11 @@ impl<'a> Iterator for SplitWhitespace<'a> {
42174227
fn size_hint(&self) -> (usize, Option<usize>) {
42184228
self.inner.size_hint()
42194229
}
4230+
4231+
#[inline]
4232+
fn last(mut self) -> Option<Self::Item> {
4233+
self.next_back()
4234+
}
42204235
}
42214236

42224237
#[stable(feature = "split_whitespace", since = "1.1.0")]
@@ -4243,6 +4258,11 @@ impl<'a> Iterator for SplitAsciiWhitespace<'a> {
42434258
fn size_hint(&self) -> (usize, Option<usize>) {
42444259
self.inner.size_hint()
42454260
}
4261+
4262+
#[inline]
4263+
fn last(mut self) -> Option<Self::Item> {
4264+
self.next_back()
4265+
}
42464266
}
42474267

42484268
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]

src/libstd/env.rs

+6
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,10 @@ impl Iterator for Args {
746746
self.inner.next().map(|s| s.into_string().unwrap())
747747
}
748748
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
749+
#[inline]
750+
fn last(mut self) -> Option<String> {
751+
self.next_back()
752+
}
749753
}
750754

751755
#[stable(feature = "env", since = "1.0.0")]
@@ -781,6 +785,8 @@ impl Iterator for ArgsOs {
781785
type Item = OsString;
782786
fn next(&mut self) -> Option<OsString> { self.inner.next() }
783787
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
788+
#[inline]
789+
fn last(mut self) -> Option<OsString> { self.next_back() }
784790
}
785791

786792
#[stable(feature = "env", since = "1.0.0")]

src/libstd/path.rs

+10
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,11 @@ impl<'a> Iterator for Iter<'a> {
888888
fn next(&mut self) -> Option<&'a OsStr> {
889889
self.inner.next().map(Component::as_os_str)
890890
}
891+
892+
#[inline]
893+
fn last(mut self) -> Option<&'a OsStr> {
894+
self.next_back()
895+
}
891896
}
892897

893898
#[stable(feature = "rust1", since = "1.0.0")]
@@ -951,6 +956,11 @@ impl<'a> Iterator for Components<'a> {
951956
}
952957
None
953958
}
959+
960+
#[inline]
961+
fn last(mut self) -> Option<Self::Item> {
962+
self.next_back()
963+
}
954964
}
955965

956966
#[stable(feature = "rust1", since = "1.0.0")]

src/libstd/sys/unix/args.rs

+2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ impl Iterator for Args {
3535
type Item = OsString;
3636
fn next(&mut self) -> Option<OsString> { self.iter.next() }
3737
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
38+
#[inline]
39+
fn last(mut self) -> Option<OsString> { self.next_back() }
3840
}
3941

4042
impl ExactSizeIterator for Args {

src/libstd/sys/wasm/args.rs

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ impl Iterator for Args {
3737
fn size_hint(&self) -> (usize, Option<usize>) {
3838
self.iter.size_hint()
3939
}
40+
#[inline]
41+
fn last(mut self) -> Option<OsString> {
42+
self.next_back()
43+
}
4044
}
4145

4246
impl ExactSizeIterator for Args {

0 commit comments

Comments
 (0)