Skip to content

Commit 966e354

Browse files
authored
Rollup merge of rust-lang#60555 - timvermeulen:rchunks_nth_back, r=scottmcm
Implement nth_back for RChunks(Exact)(Mut) Part of rust-lang#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
2 parents 85c975b + 5eb0e08 commit 966e354

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

src/libcore/slice/mod.rs

+72
Original file line numberDiff line numberDiff line change
@@ -4649,6 +4649,23 @@ impl<'a, T> DoubleEndedIterator for RChunks<'a, T> {
46494649
Some(fst)
46504650
}
46514651
}
4652+
4653+
#[inline]
4654+
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
4655+
let len = self.len();
4656+
if n >= len {
4657+
self.v = &[];
4658+
None
4659+
} else {
4660+
// can't underflow because `n < len`
4661+
let offset_from_end = (len - 1 - n) * self.chunk_size;
4662+
let end = self.v.len() - offset_from_end;
4663+
let start = end.saturating_sub(self.chunk_size);
4664+
let nth_back = &self.v[start..end];
4665+
self.v = &self.v[end..];
4666+
Some(nth_back)
4667+
}
4668+
}
46524669
}
46534670

46544671
#[stable(feature = "rchunks", since = "1.31.0")]
@@ -4774,6 +4791,24 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> {
47744791
Some(head)
47754792
}
47764793
}
4794+
4795+
#[inline]
4796+
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
4797+
let len = self.len();
4798+
if n >= len {
4799+
self.v = &mut [];
4800+
None
4801+
} else {
4802+
// can't underflow because `n < len`
4803+
let offset_from_end = (len - 1 - n) * self.chunk_size;
4804+
let end = self.v.len() - offset_from_end;
4805+
let start = end.saturating_sub(self.chunk_size);
4806+
let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
4807+
let (_, nth_back) = tmp.split_at_mut(start);
4808+
self.v = tail;
4809+
Some(nth_back)
4810+
}
4811+
}
47774812
}
47784813

47794814
#[stable(feature = "rchunks", since = "1.31.0")]
@@ -4898,6 +4933,24 @@ impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> {
48984933
Some(fst)
48994934
}
49004935
}
4936+
4937+
#[inline]
4938+
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
4939+
let len = self.len();
4940+
if n >= len {
4941+
self.v = &[];
4942+
None
4943+
} else {
4944+
// now that we know that `n` corresponds to a chunk,
4945+
// none of these operations can underflow/overflow
4946+
let offset = (len - n) * self.chunk_size;
4947+
let start = self.v.len() - offset;
4948+
let end = start + self.chunk_size;
4949+
let nth_back = &self.v[start..end];
4950+
self.v = &self.v[end..];
4951+
Some(nth_back)
4952+
}
4953+
}
49014954
}
49024955

49034956
#[stable(feature = "rchunks", since = "1.31.0")]
@@ -5016,6 +5069,25 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> {
50165069
Some(head)
50175070
}
50185071
}
5072+
5073+
#[inline]
5074+
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
5075+
let len = self.len();
5076+
if n >= len {
5077+
self.v = &mut [];
5078+
None
5079+
} else {
5080+
// now that we know that `n` corresponds to a chunk,
5081+
// none of these operations can underflow/overflow
5082+
let offset = (len - n) * self.chunk_size;
5083+
let start = self.v.len() - offset;
5084+
let end = start + self.chunk_size;
5085+
let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
5086+
let (_, nth_back) = tmp.split_at_mut(start);
5087+
self.v = tail;
5088+
Some(nth_back)
5089+
}
5090+
}
50195091
}
50205092

50215093
#[stable(feature = "rchunks", since = "1.31.0")]

src/libcore/tests/slice.rs

+52
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,19 @@ fn test_rchunks_nth() {
356356
assert_eq!(c2.next(), None);
357357
}
358358

359+
#[test]
360+
fn test_rchunks_nth_back() {
361+
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
362+
let mut c = v.rchunks(2);
363+
assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
364+
assert_eq!(c.next_back().unwrap(), &[4, 5]);
365+
366+
let v2: &[i32] = &[0, 1, 2, 3, 4];
367+
let mut c2 = v2.rchunks(3);
368+
assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]);
369+
assert_eq!(c2.next_back(), None);
370+
}
371+
359372
#[test]
360373
fn test_rchunks_last() {
361374
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
@@ -407,6 +420,19 @@ fn test_rchunks_mut_nth() {
407420
assert_eq!(c2.next(), None);
408421
}
409422

423+
#[test]
424+
fn test_rchunks_mut_nth_back() {
425+
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
426+
let mut c = v.rchunks_mut(2);
427+
assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
428+
assert_eq!(c.next_back().unwrap(), &[4, 5]);
429+
430+
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4];
431+
let mut c2 = v2.rchunks_mut(3);
432+
assert_eq!(c2.nth_back(1).unwrap(), &[2, 3, 4]);
433+
assert_eq!(c2.next_back(), None);
434+
}
435+
410436
#[test]
411437
fn test_rchunks_mut_last() {
412438
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
@@ -460,6 +486,19 @@ fn test_rchunks_exact_nth() {
460486
assert_eq!(c2.next(), None);
461487
}
462488

489+
#[test]
490+
fn test_rchunks_exact_nth_back() {
491+
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
492+
let mut c = v.rchunks_exact(2);
493+
assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
494+
assert_eq!(c.next_back().unwrap(), &[4, 5]);
495+
496+
let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
497+
let mut c2 = v2.rchunks_exact(3);
498+
assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]);
499+
assert_eq!(c2.next(), None);
500+
}
501+
463502
#[test]
464503
fn test_rchunks_exact_last() {
465504
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
@@ -518,6 +557,19 @@ fn test_rchunks_exact_mut_nth() {
518557
assert_eq!(c2.next(), None);
519558
}
520559

560+
#[test]
561+
fn test_rchunks_exact_mut_nth_back() {
562+
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
563+
let mut c = v.rchunks_exact_mut(2);
564+
assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
565+
assert_eq!(c.next_back().unwrap(), &[4, 5]);
566+
567+
let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6];
568+
let mut c2 = v2.rchunks_exact_mut(3);
569+
assert_eq!(c2.nth_back(1).unwrap(), &[4, 5, 6]);
570+
assert_eq!(c2.next(), None);
571+
}
572+
521573
#[test]
522574
fn test_rchunks_exact_mut_last() {
523575
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];

0 commit comments

Comments
 (0)