Skip to content

Commit 67e3167

Browse files
committed
slice iter: more cleanup
1 parent 4962b40 commit 67e3167

File tree

2 files changed

+40
-47
lines changed

2 files changed

+40
-47
lines changed

library/core/src/slice/iter.rs

Lines changed: 33 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,26 +1415,21 @@ impl<'a, T> Iterator for Windows<'a, T> {
14151415
#[stable(feature = "rust1", since = "1.0.0")]
14161416
impl<'a, T> DoubleEndedIterator for Windows<'a, T> {
14171417
#[inline]
1418-
fn next_back(&mut self) -> Option<&'a [T]> {
1419-
if self.size.get() > self.v.len() {
1420-
None
1421-
} else {
1422-
let ret = Some(&self.v[self.v.len() - self.size.get()..]);
1423-
self.v = &self.v[..self.v.len() - 1];
1424-
ret
1425-
}
1418+
fn next_back(&mut self) -> Option<Self::Item> {
1419+
self.nth_back(0)
14261420
}
14271421

14281422
#[inline]
14291423
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
1430-
let (end, overflow) = self.v.len().overflowing_sub(n);
1431-
if end < self.size.get() || overflow {
1424+
if let Some(end) = self.v.len().checked_sub(n)
1425+
&& let Some(start) = end.checked_sub(self.size.get())
1426+
{
1427+
let res = &self.v[start..end];
1428+
self.v = &self.v[..end - 1];
1429+
Some(res)
1430+
} else {
14321431
self.v = &self.v[..0]; // cheaper than &[]
14331432
None
1434-
} else {
1435-
let ret = &self.v[end - self.size.get()..end];
1436-
self.v = &self.v[..end - 1];
1437-
Some(ret)
14381433
}
14391434
}
14401435
}
@@ -1523,9 +1518,7 @@ impl<'a, T> Iterator for Chunks<'a, T> {
15231518
if self.v.is_empty() {
15241519
(0, Some(0))
15251520
} else {
1526-
let n = self.v.len() / self.chunk_size;
1527-
let rem = self.v.len() % self.chunk_size;
1528-
let n = if rem > 0 { n + 1 } else { n };
1521+
let n = (self.v.len() - 1) / self.chunk_size + 1;
15291522
(n, Some(n))
15301523
}
15311524
}
@@ -1613,7 +1606,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> {
16131606
None
16141607
} else {
16151608
let start = (len - 1 - n) * self.chunk_size;
1616-
let end = (start + self.chunk_size).min(self.v.len());
1609+
let end = start + (self.v.len() - start).min(self.chunk_size);
16171610
let nth_back = &self.v[start..end];
16181611
self.v = &self.v[..start];
16191612
Some(nth_back)
@@ -1903,13 +1896,10 @@ impl<'a, T> Iterator for ChunksExact<'a, T> {
19031896

19041897
#[inline]
19051898
fn next(&mut self) -> Option<&'a [T]> {
1906-
if self.v.len() < self.chunk_size {
1907-
None
1908-
} else {
1909-
let (fst, snd) = self.v.split_at(self.chunk_size);
1910-
self.v = snd;
1911-
Some(fst)
1912-
}
1899+
self.v.split_at_checked(self.chunk_size).and_then(|(chunk, rest)| {
1900+
self.v = rest;
1901+
Some(chunk)
1902+
})
19131903
}
19141904

19151905
#[inline]
@@ -1925,14 +1915,14 @@ impl<'a, T> Iterator for ChunksExact<'a, T> {
19251915

19261916
#[inline]
19271917
fn nth(&mut self, n: usize) -> Option<Self::Item> {
1928-
let (start, overflow) = n.overflowing_mul(self.chunk_size);
1929-
if start >= self.v.len() || overflow {
1918+
if let Some(start) = n.checked_mul(self.chunk_size)
1919+
&& start < self.v.len()
1920+
{
1921+
self.v = &self.v[start..];
1922+
self.next()
1923+
} else {
19301924
self.v = &self.v[..0]; // cheaper than &[]
19311925
None
1932-
} else {
1933-
let (_, snd) = self.v.split_at(start);
1934-
self.v = snd;
1935-
self.next()
19361926
}
19371927
}
19381928

@@ -2061,15 +2051,11 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> {
20612051

20622052
#[inline]
20632053
fn next(&mut self) -> Option<&'a mut [T]> {
2064-
if self.v.len() < self.chunk_size {
2065-
None
2066-
} else {
2067-
// SAFETY: self.chunk_size is inbounds because we compared above against self.v.len()
2068-
let (head, tail) = unsafe { self.v.split_at_mut(self.chunk_size) };
2069-
self.v = tail;
2070-
// SAFETY: Nothing else points to or will point to the contents of this slice.
2071-
Some(unsafe { &mut *head })
2072-
}
2054+
// SAFETY: we have `&mut self`, so are allowed to temporarily materialize a mut slice
2055+
unsafe { &mut *self.v }.split_at_mut_checked(self.chunk_size).and_then(|(chunk, rest)| {
2056+
self.v = rest;
2057+
Some(chunk)
2058+
})
20732059
}
20742060

20752061
#[inline]
@@ -2085,15 +2071,15 @@ impl<'a, T> Iterator for ChunksExactMut<'a, T> {
20852071

20862072
#[inline]
20872073
fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
2088-
let (start, overflow) = n.overflowing_mul(self.chunk_size);
2089-
if start >= self.v.len() || overflow {
2074+
if let Some(start) = n.checked_mul(self.chunk_size)
2075+
&& start < self.v.len()
2076+
{
2077+
// SAFETY: `start < self.v.len()`
2078+
self.v = unsafe { self.v.split_at_mut(start).1 };
2079+
self.next()
2080+
} else {
20902081
self.v = &mut [];
20912082
None
2092-
} else {
2093-
// SAFETY: The self.v contract ensures that any split_at_mut is valid.
2094-
let (_, snd) = unsafe { self.v.split_at_mut(start) };
2095-
self.v = snd;
2096-
self.next()
20972083
}
20982084
}
20992085

library/coretests/tests/slice.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,13 @@ fn test_chunks_exact_mut_zip_aliasing() {
432432
assert_eq!(first, (&mut [0, 1][..], &[6, 7][..]));
433433
}
434434

435+
#[test]
436+
fn test_chunks_zst() {
437+
const SIZE: usize = 16;
438+
let mut it = [(); usize::MAX].chunks(SIZE);
439+
assert_eq!(it.nth_back(0), Some(&[(); SIZE - 1][..]));
440+
}
441+
435442
#[test]
436443
fn test_rchunks_mut_zip_aliasing() {
437444
let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];

0 commit comments

Comments
 (0)