Skip to content

Commit 70cc6c9

Browse files
authored
Rollup merge of rust-lang#58064 - llogiq:vec-deque-try-rfold, r=scottmcm
override `VecDeque::try_rfold`, also update iterator This keeps the slice based iteration and updates the iterator state after each slice. It also uses a loop to reduce the amount of code. This uses unsafe code, so some thorough review would be appreciated. Cc @RalfJung
2 parents ec8ef18 + 64c915e commit 70cc6c9

File tree

3 files changed

+117
-5
lines changed

3 files changed

+117
-5
lines changed

src/liballoc/benches/vec_deque.rs

+7
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,10 @@ fn bench_mut_iter_1000(b: &mut Bencher) {
4545
black_box(sum);
4646
})
4747
}
48+
49+
#[bench]
50+
fn bench_try_fold(b: &mut Bencher) {
51+
let ring: VecDeque<_> = (0..1000).collect();
52+
53+
b.iter(|| black_box(ring.iter().try_fold(0, |a, b| Some(a + b))))
54+
}

src/liballoc/collections/vec_deque.rs

+46-5
Original file line numberDiff line numberDiff line change
@@ -2170,12 +2170,29 @@ impl<'a, T> Iterator for Iter<'a, T> {
21702170
back.iter().fold(accum, &mut f)
21712171
}
21722172

2173-
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R where
2174-
Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
2173+
fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
2174+
where
2175+
Self: Sized,
2176+
F: FnMut(B, Self::Item) -> R,
2177+
R: Try<Ok = B>,
21752178
{
2176-
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
2177-
let accum = front.iter().try_fold(init, &mut f)?;
2178-
back.iter().try_fold(accum, &mut f)
2179+
let (mut iter, final_res);
2180+
if self.tail <= self.head {
2181+
// single slice self.ring[self.tail..self.head]
2182+
iter = self.ring[self.tail..self.head].iter();
2183+
final_res = iter.try_fold(init, &mut f);
2184+
} else {
2185+
// two slices: self.ring[self.tail..], self.ring[..self.head]
2186+
let (front, back) = self.ring.split_at(self.tail);
2187+
let mut back_iter = back.iter();
2188+
let res = back_iter.try_fold(init, &mut f);
2189+
let len = self.ring.len();
2190+
self.tail = (self.ring.len() - back_iter.len()) & (len - 1);
2191+
iter = front[..self.head].iter();
2192+
final_res = iter.try_fold(res?, &mut f);
2193+
}
2194+
self.tail = self.head - iter.len();
2195+
final_res
21792196
}
21802197
}
21812198

@@ -2197,6 +2214,30 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
21972214
accum = back.iter().rfold(accum, &mut f);
21982215
front.iter().rfold(accum, &mut f)
21992216
}
2217+
2218+
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
2219+
where
2220+
Self: Sized,
2221+
F: FnMut(B, Self::Item) -> R,
2222+
R: Try<Ok = B>,
2223+
{
2224+
let (mut iter, final_res);
2225+
if self.tail <= self.head {
2226+
// single slice self.ring[self.tail..self.head]
2227+
iter = self.ring[self.tail..self.head].iter();
2228+
final_res = iter.try_rfold(init, &mut f);
2229+
} else {
2230+
// two slices: self.ring[self.tail..], self.ring[..self.head]
2231+
let (front, back) = self.ring.split_at(self.tail);
2232+
let mut front_iter = front[..self.head].iter();
2233+
let res = front_iter.try_rfold(init, &mut f);
2234+
self.head = front_iter.len();
2235+
iter = back.iter();
2236+
final_res = iter.try_rfold(res?, &mut f);
2237+
}
2238+
self.head = self.tail + iter.len();
2239+
final_res
2240+
}
22002241
}
22012242

22022243
#[stable(feature = "rust1", since = "1.0.0")]

src/liballoc/tests/vec_deque.rs

+64
Original file line numberDiff line numberDiff line change
@@ -1465,6 +1465,15 @@ fn test_try_fold_unit() {
14651465
assert_eq!(Some(()), v.into_iter().try_fold((), |(), ()| Some(())));
14661466
}
14671467

1468+
1469+
#[test]
1470+
fn test_try_fold_unit_none() {
1471+
let v: std::collections::VecDeque<()> = [(); 10].iter().cloned().collect();
1472+
let mut iter = v.into_iter();
1473+
assert!(iter.try_fold((), |_, _| None).is_none());
1474+
assert_eq!(iter.len(), 9);
1475+
}
1476+
14681477
#[test]
14691478
fn test_try_fold_rotated() {
14701479
let mut v: VecDeque<_> = (0..12).collect();
@@ -1477,3 +1486,58 @@ fn test_try_fold_rotated() {
14771486
assert_eq!(Ok::<_, ()>(66), v.iter().try_fold(0, |a, b| Ok(a + b)));
14781487
}
14791488
}
1489+
1490+
#[test]
1491+
fn test_try_fold_moves_iter() {
1492+
let v: VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect();
1493+
let mut iter = v.into_iter();
1494+
assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None);
1495+
assert_eq!(iter.next(), Some(&60));
1496+
}
1497+
1498+
#[test]
1499+
fn test_try_fold_exhaust_wrap() {
1500+
let mut v = VecDeque::with_capacity(7);
1501+
v.push_back(1);
1502+
v.push_back(1);
1503+
v.push_back(1);
1504+
v.pop_front();
1505+
v.pop_front();
1506+
let mut iter = v.iter();
1507+
let _ = iter.try_fold(0, |_, _| Some(1));
1508+
assert!(iter.is_empty());
1509+
}
1510+
1511+
#[test]
1512+
fn test_try_fold_wraparound() {
1513+
let mut v = VecDeque::with_capacity(8);
1514+
v.push_back(7);
1515+
v.push_back(8);
1516+
v.push_back(9);
1517+
v.push_front(2);
1518+
v.push_front(1);
1519+
let mut iter = v.iter();
1520+
let _ = iter.find(|&&x| x == 2);
1521+
assert_eq!(Some(&7), iter.next());
1522+
}
1523+
1524+
#[test]
1525+
fn test_try_rfold_rotated() {
1526+
let mut v: VecDeque<_> = (0..12).collect();
1527+
for n in 0..10 {
1528+
if n & 1 == 0 {
1529+
v.rotate_left(n);
1530+
} else {
1531+
v.rotate_right(n);
1532+
}
1533+
assert_eq!(Ok::<_, ()>(66), v.iter().try_rfold(0, |a, b| Ok(a + b)));
1534+
}
1535+
}
1536+
1537+
#[test]
1538+
fn test_try_rfold_moves_iter() {
1539+
let v : VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect();
1540+
let mut iter = v.into_iter();
1541+
assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None);
1542+
assert_eq!(iter.next_back(), Some(&70));
1543+
}

0 commit comments

Comments
 (0)