Skip to content

Commit 73ac5d6

Browse files
committed
Auto merge of #47180 - varkor:range-iterator-overrides, r=alexcrichton
Add iterator method specialisations to Range* Add specialised implementations of `max` for `Range`, and `last`, `min` and `max` for `RangeInclusive`, all of which lead to significant advantages in the generated assembly on x86. Note that adding specialisations of `min` and `last` for `Range` led to no benefit, and adding `sum` for `Range` and `RangeInclusive` led to type inference issues (though this is possibly still worthwhile considering the performance gain). This addresses some of the concerns in #39975.
2 parents 619ced0 + 919d643 commit 73ac5d6

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

src/libcore/iter/range.rs

+30
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,21 @@ impl<A: Step> Iterator for ops::Range<A> {
251251
self.start = self.end.clone();
252252
None
253253
}
254+
255+
#[inline]
256+
fn last(mut self) -> Option<A> {
257+
self.next_back()
258+
}
259+
260+
#[inline]
261+
fn min(mut self) -> Option<A> {
262+
self.next()
263+
}
264+
265+
#[inline]
266+
fn max(mut self) -> Option<A> {
267+
self.next_back()
268+
}
254269
}
255270

256271
// These macros generate `ExactSizeIterator` impls for various range types.
@@ -367,6 +382,21 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
367382
self.end.replace_zero();
368383
None
369384
}
385+
386+
#[inline]
387+
fn last(mut self) -> Option<A> {
388+
self.next_back()
389+
}
390+
391+
#[inline]
392+
fn min(mut self) -> Option<A> {
393+
self.next()
394+
}
395+
396+
#[inline]
397+
fn max(mut self) -> Option<A> {
398+
self.next_back()
399+
}
370400
}
371401

372402
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]

src/libcore/tests/iter.rs

+45
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,51 @@ fn test_range_step() {
13521352
assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX)));
13531353
}
13541354

1355+
#[test]
1356+
fn test_range_last_max() {
1357+
assert_eq!((0..20).last(), Some(19));
1358+
assert_eq!((-20..0).last(), Some(-1));
1359+
assert_eq!((5..5).last(), None);
1360+
1361+
assert_eq!((0..20).max(), Some(19));
1362+
assert_eq!((-20..0).max(), Some(-1));
1363+
assert_eq!((5..5).max(), None);
1364+
}
1365+
1366+
#[test]
1367+
fn test_range_inclusive_last_max() {
1368+
assert_eq!((0..=20).last(), Some(20));
1369+
assert_eq!((-20..=0).last(), Some(0));
1370+
assert_eq!((5..=5).last(), Some(5));
1371+
let mut r = 10..=10;
1372+
r.next();
1373+
assert_eq!(r.last(), None);
1374+
1375+
assert_eq!((0..=20).max(), Some(20));
1376+
assert_eq!((-20..=0).max(), Some(0));
1377+
assert_eq!((5..=5).max(), Some(5));
1378+
let mut r = 10..=10;
1379+
r.next();
1380+
assert_eq!(r.max(), None);
1381+
}
1382+
1383+
#[test]
1384+
fn test_range_min() {
1385+
assert_eq!((0..20).min(), Some(0));
1386+
assert_eq!((-20..0).min(), Some(-20));
1387+
assert_eq!((5..5).min(), None);
1388+
}
1389+
1390+
#[test]
1391+
fn test_range_inclusive_min() {
1392+
assert_eq!((0..=20).min(), Some(0));
1393+
assert_eq!((-20..=0).min(), Some(-20));
1394+
assert_eq!((5..=5).min(), Some(5));
1395+
let mut r = 10..=10;
1396+
r.next();
1397+
assert_eq!(r.min(), None);
1398+
}
1399+
13551400
#[test]
13561401
fn test_repeat() {
13571402
let mut it = repeat(42);

0 commit comments

Comments
 (0)