about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-05-29 08:15:51 +0200
committerGitHub <noreply@github.com>2019-05-29 08:15:51 +0200
commit23b9b8320b97adbd3c7c3c3b939d5d162801d9c0 (patch)
tree3a940440fd604d12df0eec8aded5bbf5054516ea /src/libcore
parent61545b697568a9e590e89585961b5f78b3a7df53 (diff)
parent5eb0e08d0feab69f9e5f3b6881bde328a9105c96 (diff)
downloadrust-23b9b8320b97adbd3c7c3c3b939d5d162801d9c0.tar.gz
rust-23b9b8320b97adbd3c7c3c3b939d5d162801d9c0.zip
Rollup merge of #60555 - timvermeulen:rchunks_nth_back, r=scottmcm
Implement nth_back for RChunks(Exact)(Mut)

Part of #54054.

These implementations may not be optimal because of the use of `self.len()`, but it's quite cheap and simplifies the code a lot.

There's quite some duplication going on here, I wouldn't mind cleaning this up later. A good next step would probably be to add private `split_off_up_to`/`split_off_from` helper methods for slices since their behavior is commonly useful throughout the `Chunks` types.

r? @scottmcm
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/slice/mod.rs72
-rw-r--r--src/libcore/tests/slice.rs52
2 files changed, 124 insertions, 0 deletions
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 50d2ba0d3ef..1c67e750e40 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -4649,6 +4649,23 @@ impl<'a, T> DoubleEndedIterator for RChunks<'a, T> {
             Some(fst)
         }
     }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &[];
+            None
+        } else {
+            // can't underflow because `n < len`
+            let offset_from_end = (len - 1 - n) * self.chunk_size;
+            let end = self.v.len() - offset_from_end;
+            let start = end.saturating_sub(self.chunk_size);
+            let nth_back = &self.v[start..end];
+            self.v = &self.v[end..];
+            Some(nth_back)
+        }
+    }
 }
 
 #[stable(feature = "rchunks", since = "1.31.0")]
@@ -4774,6 +4791,24 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> {
             Some(head)
         }
     }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &mut [];
+            None
+        } else {
+            // can't underflow because `n < len`
+            let offset_from_end = (len - 1 - n) * self.chunk_size;
+            let end = self.v.len() - offset_from_end;
+            let start = end.saturating_sub(self.chunk_size);
+            let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+            let (_, nth_back) = tmp.split_at_mut(start);
+            self.v = tail;
+            Some(nth_back)
+        }
+    }
 }
 
 #[stable(feature = "rchunks", since = "1.31.0")]
@@ -4898,6 +4933,24 @@ impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> {
             Some(fst)
         }
     }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &[];
+            None
+        } else {
+            // now that we know that `n` corresponds to a chunk,
+            // none of these operations can underflow/overflow
+            let offset = (len - n) * self.chunk_size;
+            let start = self.v.len() - offset;
+            let end = start + self.chunk_size;
+            let nth_back = &self.v[start..end];
+            self.v = &self.v[end..];
+            Some(nth_back)
+        }
+    }
 }
 
 #[stable(feature = "rchunks", since = "1.31.0")]
@@ -5016,6 +5069,25 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> {
             Some(head)
         }
     }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+        let len = self.len();
+        if n >= len {
+            self.v = &mut [];
+            None
+        } else {
+            // now that we know that `n` corresponds to a chunk,
+            // none of these operations can underflow/overflow
+            let offset = (len - n) * self.chunk_size;
+            let start = self.v.len() - offset;
+            let end = start + self.chunk_size;
+            let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+            let (_, nth_back) = tmp.split_at_mut(start);
+            self.v = tail;
+            Some(nth_back)
+        }
+    }
 }
 
 #[stable(feature = "rchunks", since = "1.31.0")]
diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs
index acf6b03791f..cd520a052a0 100644
--- a/src/libcore/tests/slice.rs
+++ b/src/libcore/tests/slice.rs
@@ -357,6 +357,19 @@ fn test_rchunks_nth() {
 }
 
 #[test]
+fn test_rchunks_nth_back() {
+    let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+    let mut c = v.rchunks(2);
+    assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+    assert_eq!(c.next_back().unwrap(), &[4, 5]);
+
+    let v2: &[i32] = &[0, 1, 2, 3, 4];
+    let mut c2 = v2.rchunks(3);
+    assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]);
+    assert_eq!(c2.next_back(), None);
+}
+
+#[test]
 fn test_rchunks_last() {
     let v: &[i32] = &[0, 1, 2, 3, 4, 5];
     let c = v.rchunks(2);
@@ -408,6 +421,19 @@ fn test_rchunks_mut_nth() {
 }
 
 #[test]
+fn test_rchunks_mut_nth_back() {
+    let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+    let mut c = v.rchunks_mut(2);
+    assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+    assert_eq!(c.next_back().unwrap(), &[4, 5]);
+
+    let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
+    let mut c2 = v2.rchunks_mut(3);
+    assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]);
+    assert_eq!(c2.next_back(), None);
+}
+
+#[test]
 fn test_rchunks_mut_last() {
     let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
     let c = v.rchunks_mut(2);
@@ -461,6 +487,19 @@ fn test_rchunks_exact_nth() {
 }
 
 #[test]
+fn test_rchunks_exact_nth_back() {
+    let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+    let mut c = v.rchunks_exact(2);
+    assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+    assert_eq!(c.next_back().unwrap(), &[4, 5]);
+
+    let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
+    let mut c2 = v2.rchunks_exact(3);
+    assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]);
+    assert_eq!(c2.next(), None);
+}
+
+#[test]
 fn test_rchunks_exact_last() {
     let v: &[i32] = &[0, 1, 2, 3, 4, 5];
     let c = v.rchunks_exact(2);
@@ -519,6 +558,19 @@ fn test_rchunks_exact_mut_nth() {
 }
 
 #[test]
+fn test_rchunks_exact_mut_nth_back() {
+    let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+    let mut c = v.rchunks_exact_mut(2);
+    assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+    assert_eq!(c.next_back().unwrap(), &[4, 5]);
+
+    let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
+    let mut c2 = v2.rchunks_exact_mut(3);
+    assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]);
+    assert_eq!(c2.next(), None);
+}
+
+#[test]
 fn test_rchunks_exact_mut_last() {
     let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
     let c = v.rchunks_exact_mut(2);