From e6498670868810b7d232223487e8f2019a6ebdbb Mon Sep 17 00:00:00 2001 From: Kornel Date: Sun, 16 Mar 2025 16:17:33 +0000 Subject: [PATCH 1/3] Optimize slice Iter::nth --- library/core/src/slice/iter.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index d48248749c265..b1a19e3427d64 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1536,17 +1536,15 @@ impl<'a, T> Iterator for Chunks<'a, T> { #[inline] fn nth(&mut self, n: usize) -> Option { let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &[]; - None - } else { - let end = match start.checked_add(self.chunk_size) { - Some(sum) => cmp::min(self.v.len(), sum), - None => self.v.len(), - }; - let nth = &self.v[start..end]; - self.v = &self.v[end..]; + // min(len) makes a wrong start harmless, but enables optimizing this to brachless code + let chunk_start = &self.v[start.min(self.v.len())..]; + let (nth, remainder) = chunk_start.split_at(self.chunk_size.min(chunk_start.len())); + if !overflow && start < self.v.len() { + self.v = remainder; Some(nth) + } else { + self.v = &self.v[..0]; // cheaper than &[] + None } } From 89477aff04a4d8f837a50deb62416cf33ecf766c Mon Sep 17 00:00:00 2001 From: Kornel Date: Sun, 16 Mar 2025 16:48:41 +0000 Subject: [PATCH 2/3] Optimize slice Windows::nth Generates branchless code --- library/core/src/slice/iter.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index b1a19e3427d64..e9c27ddbbbaee 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1380,14 +1380,16 @@ impl<'a, T> Iterator for Windows<'a, T> { #[inline] fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = self.size.get().overflowing_add(n); - if end > self.v.len() || overflow { - self.v = &[]; - None - } else { - let nth = &self.v[n..end]; - self.v = &self.v[n + 1..]; + let size = self.size.get(); + if let Some(rest) = self.v.get(n..) + && let Some(nth) = rest.get(..size) + { + self.v = &rest[1..]; Some(nth) + } else { + // setting length to 0 is cheaper than overwriting the pointer when assigning &[] + self.v = &self.v[..0]; + None } } From 9f2f1aa08354019113f39672228fc62583e6a1ed Mon Sep 17 00:00:00 2001 From: Kornel Date: Sun, 16 Mar 2025 16:17:16 +0000 Subject: [PATCH 3/3] Optimize setting the slice to empty in slice Iter This avoids generating extra instructions that needlessly modify the slice's pointer --- library/core/src/slice/iter.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index e9c27ddbbbaee..f507ee563ac07 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -1388,7 +1388,7 @@ impl<'a, T> Iterator for Windows<'a, T> { Some(nth) } else { // setting length to 0 is cheaper than overwriting the pointer when assigning &[] - self.v = &self.v[..0]; + self.v = &self.v[..0]; // cheaper than &[] None } } @@ -1429,7 +1429,7 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> { fn nth_back(&mut self, n: usize) -> Option { let (end, overflow) = self.v.len().overflowing_sub(n); if end < self.size.get() || overflow { - self.v = &[]; + self.v = &self.v[..0]; // cheaper than &[] None } else { let ret = &self.v[end - self.size.get()..end]; @@ -1609,7 +1609,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); if n >= len { - self.v = &[]; + self.v = &self.v[..0]; // cheaper than &[] None } else { let start = (len - 1 - n) * self.chunk_size; @@ -1933,7 +1933,7 @@ impl<'a, T> Iterator for ChunksExact<'a, T> { fn nth(&mut self, n: usize) -> Option { let (start, overflow) = n.overflowing_mul(self.chunk_size); if start >= self.v.len() || overflow { - self.v = &[]; + self.v = &self.v[..0]; // cheaper than &[] None } else { let (_, snd) = self.v.split_at(start); @@ -1971,7 +1971,7 @@ impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> { fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); if n >= len { - self.v = &[]; + self.v = &self.v[..0]; // cheaper than &[] None } else { let start = (len - 1 - n) * self.chunk_size; @@ -2638,7 +2638,7 @@ impl<'a, T> Iterator for RChunks<'a, T> { fn nth(&mut self, n: usize) -> Option { let (end, overflow) = n.overflowing_mul(self.chunk_size); if end >= self.v.len() || overflow { - self.v = &[]; + self.v = &self.v[..0]; // cheaper than &[] None } else { // Can't underflow because of the check above @@ -2695,7 +2695,7 @@ impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); if n >= len { - self.v = &[]; + self.v = &self.v[..0]; // cheaper than &[] None } else { // can't underflow because `n < len` @@ -3023,7 +3023,7 @@ impl<'a, T> Iterator for RChunksExact<'a, T> { fn nth(&mut self, n: usize) -> Option { let (end, overflow) = n.overflowing_mul(self.chunk_size); if end >= self.v.len() || overflow { - self.v = &[]; + self.v = &self.v[..0]; // cheaper than &[] None } else { let (fst, _) = self.v.split_at(self.v.len() - end); @@ -3062,7 +3062,7 @@ impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { fn nth_back(&mut self, n: usize) -> Option { let len = self.len(); if n >= len { - self.v = &[]; + self.v = &self.v[..0]; // cheaper than &[] None } else { // now that we know that `n` corresponds to a chunk,