Skip to content

Commit db16e17

Browse files
committed
When possible without changing semantics, implement Iterator::last in terms of DoubleEndedIterator::next_back for types in liballoc and libcore.
Provided that the iterator has finite length and does not trigger user-provided code, this is safe. What follows is a full list of the DoubleEndedIterators in liballoc/libcore and whether this optimization is safe, and if not, why not. src/liballoc/boxed.rs Box: Pass through to avoid defeating optimization of the underlying DoubleIterator implementation. This has no correctness impact. src/liballoc/collections/binary_heap.rs Iter: Pass through to avoid defeating optimizations on slice::Iter IntoIter: Not safe, changes Drop order Drain: Not safe, changes Drop order src/liballoc/collections/btree/map.rs Iter: Safe to call next_back, invokes no user defined code. IterMut: ditto IntoIter: Not safe, changes Drop order Keys: Safe to call next_back, invokes no user defined code. Values: ditto ValuesMut: ditto Range: ditto RangeMut: ditto src/liballoc/collections/btree/set.rs Iter: Safe to call next_back, invokes no user defined code. IntoIter: Not safe, changes Drop order Range: Safe to call next_back, invokes no user defined code. src/liballoc/collections/linked_list.rs Iter: Safe to call next_back, invokes no user defined code. IterMut: ditto IntoIter: Not safe, changes Drop order src/liballoc/collections/vec_deque.rs Iter: Safe to call next_back, invokes no user defined code. IterMut: ditto IntoIter: Not safe, changes Drop order Drain: ditto src/liballoc/string.rs Drain: Safe because return type is a primitive (char) src/liballoc/vec.rs IntoIter: Not safe, changes Drop order Drain: ditto Splice: ditto src/libcore/ascii.rs EscapeDefault: Safe because return type is a primitive (u8) src/libcore/iter/adapters/chain.rs Chain: Not safe, invokes user defined code (Iterator impl) src/libcore/iter/adapters/flatten.rs FlatMap: Not safe, invokes user defined code (Iterator impl) Flatten: ditto FlattenCompat: ditto src/libcore/iter/adapters/mod.rs Rev: Not safe, invokes user defined code (Iterator impl) Copied: ditto Cloned: Not safe, invokes user defined code (Iterator impl and T::clone) Map: Not safe, invokes user defined code (Iterator impl + closure) Filter: ditto FilterMap: ditto Enumerate: Not safe, invokes user defined code (Iterator impl) Skip: ditto Fuse: ditto Inspect: ditto src/libcore/iter/adapters/zip.rs Zip: Not safe, invokes user defined code (Iterator impl) src/libcore/iter/range.rs ops::Range: Not safe, changes Drop order, but ALREADY HAS SPECIALIZATION ops::RangeInclusive: ditto src/libcore/iter/sources.rs Repeat: Not safe, calling last should iloop. Empty: No point, iterator is at most one item long. Once: ditto OnceWith: ditto src/libcore/option.rs Item: No point, iterator is at most one item long. Iter: ditto IterMut: ditto IntoIter: ditto src/libcore/result.rs Iter: No point, iterator is at most one item long IterMut: ditto IntoIter: ditto src/libcore/slice/mod.rs Split: Not safe, invokes user defined closure SplitMut: ditto RSplit: ditto RSplitMut: ditto Windows: Safe, already has specialization Chunks: ditto ChunksMut: ditto ChunksExact: ditto ChunksExactMut: ditto RChunks: ditto RChunksMut: ditto RChunksExact: ditto RChunksExactMut: ditto src/libcore/str/mod.rs Chars: Safe, already has specialization CharIndices: ditto Bytes: ditto Lines: Safe to call next_back, invokes no user defined code. LinesAny: Deprecated Everything that is generic over P: Pattern: Not safe because Pattern invokes user defined code. SplitWhitespace: Safe to call next_back, invokes no user defined code. SplitAsciiWhitespace: ditto
1 parent 848e0a2 commit db16e17

File tree

9 files changed

+89
-0
lines changed

9 files changed

+89
-0
lines changed

src/liballoc/boxed.rs

+8
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,14 @@ impl<I: Iterator + ?Sized> Iterator for Box<I> {
716716
(**self).nth(n)
717717
}
718718
}
719+
720+
#[stable(feature = "rust1", since = "1.0.0")]
721+
impl<I: Iterator + Sized> Iterator for Box<I> {
722+
fn last(self) -> Option<I::Item> where I: Sized {
723+
(*self).last()
724+
}
725+
}
726+
719727
#[stable(feature = "rust1", since = "1.0.0")]
720728
impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for Box<I> {
721729
fn next_back(&mut self) -> Option<I::Item> {

src/liballoc/collections/binary_heap.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,11 @@ impl<'a, T> Iterator for Iter<'a, T> {
10351035
fn size_hint(&self) -> (usize, Option<usize>) {
10361036
self.iter.size_hint()
10371037
}
1038+
1039+
#[inline]
1040+
fn last(self) -> Option<&'a T> {
1041+
self.iter.last()
1042+
}
10381043
}
10391044

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

src/liballoc/collections/btree/map.rs

+28
Original file line numberDiff line numberDiff line change
@@ -1193,6 +1193,10 @@ 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+
fn last(mut self) -> Option<(&'a K, &'a V)> {
1198+
self.next_back()
1199+
}
11961200
}
11971201

11981202
#[stable(feature = "fused", since = "1.26.0")]
@@ -1253,6 +1257,10 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
12531257
fn size_hint(&self) -> (usize, Option<usize>) {
12541258
(self.length, Some(self.length))
12551259
}
1260+
1261+
fn last(mut self) -> Option<(&'a K, &'a mut V)> {
1262+
self.next_back()
1263+
}
12561264
}
12571265

12581266
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1421,6 +1429,10 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> {
14211429
fn size_hint(&self) -> (usize, Option<usize>) {
14221430
self.inner.size_hint()
14231431
}
1432+
1433+
fn last(mut self) -> Option<&'a K> {
1434+
self.next_back()
1435+
}
14241436
}
14251437

14261438
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1458,6 +1470,10 @@ impl<'a, K, V> Iterator for Values<'a, K, V> {
14581470
fn size_hint(&self) -> (usize, Option<usize>) {
14591471
self.inner.size_hint()
14601472
}
1473+
1474+
fn last(mut self) -> Option<&'a V> {
1475+
self.next_back()
1476+
}
14611477
}
14621478

14631479
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1495,6 +1511,10 @@ impl<'a, K, V> Iterator for Range<'a, K, V> {
14951511
unsafe { Some(self.next_unchecked()) }
14961512
}
14971513
}
1514+
1515+
fn last(mut self) -> Option<(&'a K, &'a V)> {
1516+
self.next_back()
1517+
}
14981518
}
14991519

15001520
#[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -1508,6 +1528,10 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
15081528
fn size_hint(&self) -> (usize, Option<usize>) {
15091529
self.inner.size_hint()
15101530
}
1531+
1532+
fn last(mut self) -> Option<&'a mut V> {
1533+
self.next_back()
1534+
}
15111535
}
15121536

15131537
#[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -1626,6 +1650,10 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> {
16261650
unsafe { Some(self.next_unchecked()) }
16271651
}
16281652
}
1653+
1654+
fn last(mut self) -> Option<(&'a K, &'a mut V)> {
1655+
self.next_back()
1656+
}
16291657
}
16301658

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

src/liballoc/collections/btree/set.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,9 @@ impl<'a, T> Iterator for Iter<'a, T> {
10191019
fn size_hint(&self) -> (usize, Option<usize>) {
10201020
self.iter.size_hint()
10211021
}
1022+
fn last(mut self) -> Option<&'a T> {
1023+
self.next_back()
1024+
}
10221025
}
10231026
#[stable(feature = "rust1", since = "1.0.0")]
10241027
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
@@ -1073,6 +1076,10 @@ impl<'a, T> Iterator for Range<'a, T> {
10731076
fn next(&mut self) -> Option<&'a T> {
10741077
self.iter.next().map(|(k, _)| k)
10751078
}
1079+
1080+
fn last(mut self) -> Option<&'a T> {
1081+
self.next_back()
1082+
}
10761083
}
10771084

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

src/liballoc/collections/linked_list.rs

+10
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,11 @@ impl<'a, T> Iterator for Iter<'a, T> {
832832
fn size_hint(&self) -> (usize, Option<usize>) {
833833
(self.len, Some(self.len))
834834
}
835+
836+
#[inline]
837+
fn last(mut self) -> Option<&'a T> {
838+
self.next_back()
839+
}
835840
}
836841

837842
#[stable(feature = "rust1", since = "1.0.0")]
@@ -881,6 +886,11 @@ impl<'a, T> Iterator for IterMut<'a, T> {
881886
fn size_hint(&self) -> (usize, Option<usize>) {
882887
(self.len, Some(self.len))
883888
}
889+
890+
#[inline]
891+
fn last(mut self) -> Option<&'a mut T> {
892+
self.next_back()
893+
}
884894
}
885895

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

src/liballoc/collections/vec_deque.rs

+10
Original file line numberDiff line numberDiff line change
@@ -2206,6 +2206,11 @@ impl<'a, T> Iterator for Iter<'a, T> {
22062206
self.tail = self.head - iter.len();
22072207
final_res
22082208
}
2209+
2210+
#[inline]
2211+
fn last(mut self) -> Option<&'a T> {
2212+
self.next_back()
2213+
}
22092214
}
22102215

22112216
#[stable(feature = "rust1", since = "1.0.0")]
@@ -2319,6 +2324,11 @@ impl<'a, T> Iterator for IterMut<'a, T> {
23192324
accum = front.iter_mut().fold(accum, &mut f);
23202325
back.iter_mut().fold(accum, &mut f)
23212326
}
2327+
2328+
#[inline]
2329+
fn last(mut self) -> Option<&'a mut T> {
2330+
self.next_back()
2331+
}
23222332
}
23232333

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

src/liballoc/string.rs

+5
Original file line numberDiff line numberDiff line change
@@ -2385,6 +2385,11 @@ impl Iterator for Drain<'_> {
23852385
fn size_hint(&self) -> (usize, Option<usize>) {
23862386
self.iter.size_hint()
23872387
}
2388+
2389+
#[inline]
2390+
fn last(mut self) -> Option<char> {
2391+
self.next_back()
2392+
}
23882393
}
23892394

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

src/libcore/ascii.rs

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ 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+
fn last(mut self) -> Option<u8> { self.next_back() }
120121
}
121122
#[stable(feature = "rust1", since = "1.0.0")]
122123
impl DoubleEndedIterator for EscapeDefault {

src/libcore/str/mod.rs

+15
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<&'a str> {
1339+
self.next_back()
1340+
}
13361341
}
13371342

13381343
#[stable(feature = "rust1", since = "1.0.0")]
@@ -4241,6 +4246,11 @@ impl<'a> Iterator for SplitWhitespace<'a> {
42414246
fn size_hint(&self) -> (usize, Option<usize>) {
42424247
self.inner.size_hint()
42434248
}
4249+
4250+
#[inline]
4251+
fn last(mut self) -> Option<&'a str> {
4252+
self.next_back()
4253+
}
42444254
}
42454255

42464256
#[stable(feature = "split_whitespace", since = "1.1.0")]
@@ -4267,6 +4277,11 @@ impl<'a> Iterator for SplitAsciiWhitespace<'a> {
42674277
fn size_hint(&self) -> (usize, Option<usize>) {
42684278
self.inner.size_hint()
42694279
}
4280+
4281+
#[inline]
4282+
fn last(mut self) -> Option<&'a str> {
4283+
self.next_back()
4284+
}
42704285
}
42714286

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

0 commit comments

Comments
 (0)