Skip to content

Commit 9689ada

Browse files
committed
Auto merge of #56842 - scottmcm:vecdeque-rotate, r=alexcrichton
Add unstable VecDeque::rotate_{left|right} Like the ones on slices, but more efficient because vecdeque is a circular buffer. Issue that proposed this: #56686 ~~:bomb: Please someone look very carefully at the `unsafe` in this! The `wrap_copy` seems to be exactly what this method needs, and the `len` passed to it is never more than half the length of the deque, but I haven't managed to prove to myself that it's correct :bomb:~~ I think I proved that this code meets the requirement of the unsafe code it's calling; please double-check, of course.
2 parents 24667aa + cbe9abb commit 9689ada

File tree

3 files changed

+248
-1
lines changed

3 files changed

+248
-1
lines changed

src/liballoc/collections/vec_deque.rs

+112
Original file line numberDiff line numberDiff line change
@@ -1927,6 +1927,118 @@ impl<T> VecDeque<T> {
19271927
self.truncate(new_len);
19281928
}
19291929
}
1930+
1931+
/// Rotates the double-ended queue `mid` places to the left.
1932+
///
1933+
/// Equivalently,
1934+
/// - Rotates item `mid` into the first position.
1935+
/// - Pops the first `mid` items and pushes them to the end.
1936+
/// - Rotates `len() - mid` places to the right.
1937+
///
1938+
/// # Panics
1939+
///
1940+
/// If `mid` is greater than `len()`. Note that `mid == len()`
1941+
/// does _not_ panic and is a no-op rotation.
1942+
///
1943+
/// # Complexity
1944+
///
1945+
/// Takes `O(min(mid, len() - mid))` time and no extra space.
1946+
///
1947+
/// # Examples
1948+
///
1949+
/// ```
1950+
/// #![feature(vecdeque_rotate)]
1951+
///
1952+
/// use std::collections::VecDeque;
1953+
///
1954+
/// let mut buf: VecDeque<_> = (0..10).collect();
1955+
///
1956+
/// buf.rotate_left(3);
1957+
/// assert_eq!(buf, [3, 4, 5, 6, 7, 8, 9, 0, 1, 2]);
1958+
///
1959+
/// for i in 1..10 {
1960+
/// assert_eq!(i * 3 % 10, buf[0]);
1961+
/// buf.rotate_left(3);
1962+
/// }
1963+
/// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1964+
/// ```
1965+
#[unstable(feature = "vecdeque_rotate", issue = "56686")]
1966+
pub fn rotate_left(&mut self, mid: usize) {
1967+
assert!(mid <= self.len());
1968+
let k = self.len() - mid;
1969+
if mid <= k {
1970+
unsafe { self.rotate_left_inner(mid) }
1971+
} else {
1972+
unsafe { self.rotate_right_inner(k) }
1973+
}
1974+
}
1975+
1976+
/// Rotates the double-ended queue `k` places to the right.
1977+
///
1978+
/// Equivalently,
1979+
/// - Rotates the first item into position `k`.
1980+
/// - Pops the last `k` items and pushes them to the front.
1981+
/// - Rotates `len() - k` places to the left.
1982+
///
1983+
/// # Panics
1984+
///
1985+
/// If `k` is greater than `len()`. Note that `k == len()`
1986+
/// does _not_ panic and is a no-op rotation.
1987+
///
1988+
/// # Complexity
1989+
///
1990+
/// Takes `O(min(k, len() - k))` time and no extra space.
1991+
///
1992+
/// # Examples
1993+
///
1994+
/// ```
1995+
/// #![feature(vecdeque_rotate)]
1996+
///
1997+
/// use std::collections::VecDeque;
1998+
///
1999+
/// let mut buf: VecDeque<_> = (0..10).collect();
2000+
///
2001+
/// buf.rotate_right(3);
2002+
/// assert_eq!(buf, [7, 8, 9, 0, 1, 2, 3, 4, 5, 6]);
2003+
///
2004+
/// for i in 1..10 {
2005+
/// assert_eq!(0, buf[i * 3 % 10]);
2006+
/// buf.rotate_right(3);
2007+
/// }
2008+
/// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
2009+
/// ```
2010+
#[unstable(feature = "vecdeque_rotate", issue = "56686")]
2011+
pub fn rotate_right(&mut self, k: usize) {
2012+
assert!(k <= self.len());
2013+
let mid = self.len() - k;
2014+
if k <= mid {
2015+
unsafe { self.rotate_right_inner(k) }
2016+
} else {
2017+
unsafe { self.rotate_left_inner(mid) }
2018+
}
2019+
}
2020+
2021+
// Safety: the following two methods require that the rotation amount
2022+
// be less than half the length of the deque.
2023+
//
2024+
// `wrap_copy` requres that `min(x, cap() - x) + copy_len <= cap()`,
2025+
// but than `min` is never more than half the capacity, regardless of x,
2026+
// so it's sound to call here because we're calling with something
2027+
// less than half the length, which is never above half the capacity.
2028+
2029+
unsafe fn rotate_left_inner(&mut self, mid: usize) {
2030+
debug_assert!(mid * 2 <= self.len());
2031+
self.wrap_copy(self.head, self.tail, mid);
2032+
self.head = self.wrap_add(self.head, mid);
2033+
self.tail = self.wrap_add(self.tail, mid);
2034+
}
2035+
2036+
unsafe fn rotate_right_inner(&mut self, k: usize) {
2037+
debug_assert!(k * 2 <= self.len());
2038+
self.head = self.wrap_sub(self.head, k);
2039+
self.tail = self.wrap_sub(self.tail, k);
2040+
self.wrap_copy(self.tail, self.head, k);
2041+
}
19302042
}
19312043

19322044
impl<T: Clone> VecDeque<T> {

src/liballoc/tests/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
#![feature(drain_filter)]
1414
#![feature(exact_size_is_empty)]
1515
#![feature(pattern)]
16+
#![feature(repeat_generic_slice)]
1617
#![feature(slice_sort_by_cached_key)]
1718
#![feature(str_escape)]
1819
#![feature(try_reserve)]
1920
#![feature(unboxed_closures)]
20-
#![feature(repeat_generic_slice)]
21+
#![feature(vecdeque_rotate)]
2122

2223
extern crate core;
2324
extern crate rand;

src/liballoc/tests/vec_deque.rs

+134
Original file line numberDiff line numberDiff line change
@@ -1309,3 +1309,137 @@ fn test_try_reserve_exact() {
13091309
}
13101310

13111311
}
1312+
1313+
#[test]
1314+
fn test_rotate_nop() {
1315+
let mut v: VecDeque<_> = (0..10).collect();
1316+
assert_unchanged(&v);
1317+
1318+
v.rotate_left(0);
1319+
assert_unchanged(&v);
1320+
1321+
v.rotate_left(10);
1322+
assert_unchanged(&v);
1323+
1324+
v.rotate_right(0);
1325+
assert_unchanged(&v);
1326+
1327+
v.rotate_right(10);
1328+
assert_unchanged(&v);
1329+
1330+
v.rotate_left(3);
1331+
v.rotate_right(3);
1332+
assert_unchanged(&v);
1333+
1334+
v.rotate_right(3);
1335+
v.rotate_left(3);
1336+
assert_unchanged(&v);
1337+
1338+
v.rotate_left(6);
1339+
v.rotate_right(6);
1340+
assert_unchanged(&v);
1341+
1342+
v.rotate_right(6);
1343+
v.rotate_left(6);
1344+
assert_unchanged(&v);
1345+
1346+
v.rotate_left(3);
1347+
v.rotate_left(7);
1348+
assert_unchanged(&v);
1349+
1350+
v.rotate_right(4);
1351+
v.rotate_right(6);
1352+
assert_unchanged(&v);
1353+
1354+
v.rotate_left(1);
1355+
v.rotate_left(2);
1356+
v.rotate_left(3);
1357+
v.rotate_left(4);
1358+
assert_unchanged(&v);
1359+
1360+
v.rotate_right(1);
1361+
v.rotate_right(2);
1362+
v.rotate_right(3);
1363+
v.rotate_right(4);
1364+
assert_unchanged(&v);
1365+
1366+
fn assert_unchanged(v: &VecDeque<i32>) {
1367+
assert_eq!(v, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
1368+
}
1369+
}
1370+
1371+
#[test]
1372+
fn test_rotate_left_parts() {
1373+
let mut v: VecDeque<_> = (1..=7).collect();
1374+
v.rotate_left(2);
1375+
assert_eq!(v.as_slices(), (&[3, 4, 5, 6, 7, 1][..], &[2][..]));
1376+
v.rotate_left(2);
1377+
assert_eq!(v.as_slices(), (&[5, 6, 7, 1][..], &[2, 3, 4][..]));
1378+
v.rotate_left(2);
1379+
assert_eq!(v.as_slices(), (&[7, 1][..], &[2, 3, 4, 5, 6][..]));
1380+
v.rotate_left(2);
1381+
assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7, 1][..], &[][..]));
1382+
v.rotate_left(2);
1383+
assert_eq!(v.as_slices(), (&[4, 5, 6, 7, 1, 2][..], &[3][..]));
1384+
v.rotate_left(2);
1385+
assert_eq!(v.as_slices(), (&[6, 7, 1, 2][..], &[3, 4, 5][..]));
1386+
v.rotate_left(2);
1387+
assert_eq!(v.as_slices(), (&[1, 2][..], &[3, 4, 5, 6, 7][..]));
1388+
}
1389+
1390+
#[test]
1391+
fn test_rotate_right_parts() {
1392+
let mut v: VecDeque<_> = (1..=7).collect();
1393+
v.rotate_right(2);
1394+
assert_eq!(v.as_slices(), (&[6, 7][..], &[1, 2, 3, 4, 5][..]));
1395+
v.rotate_right(2);
1396+
assert_eq!(v.as_slices(), (&[4, 5, 6, 7][..], &[1, 2, 3][..]));
1397+
v.rotate_right(2);
1398+
assert_eq!(v.as_slices(), (&[2, 3, 4, 5, 6, 7][..], &[1][..]));
1399+
v.rotate_right(2);
1400+
assert_eq!(v.as_slices(), (&[7, 1, 2, 3, 4, 5, 6][..], &[][..]));
1401+
v.rotate_right(2);
1402+
assert_eq!(v.as_slices(), (&[5, 6][..], &[7, 1, 2, 3, 4][..]));
1403+
v.rotate_right(2);
1404+
assert_eq!(v.as_slices(), (&[3, 4, 5, 6][..], &[7, 1, 2][..]));
1405+
v.rotate_right(2);
1406+
assert_eq!(v.as_slices(), (&[1, 2, 3, 4, 5, 6][..], &[7][..]));
1407+
}
1408+
1409+
#[test]
1410+
fn test_rotate_left_random() {
1411+
let shifts = [
1412+
6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1,
1413+
4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11,
1414+
9, 4, 12, 3, 12, 9, 11, 1, 7, 9, 7, 2,
1415+
];
1416+
let n = 12;
1417+
let mut v: VecDeque<_> = (0..n).collect();
1418+
let mut total_shift = 0;
1419+
for shift in shifts.iter().cloned() {
1420+
v.rotate_left(shift);
1421+
total_shift += shift;
1422+
for i in 0..n {
1423+
assert_eq!(v[i], (i + total_shift) % n);
1424+
}
1425+
}
1426+
}
1427+
1428+
#[test]
1429+
fn test_rotate_right_random() {
1430+
let shifts = [
1431+
6, 1, 0, 11, 12, 1, 11, 7, 9, 3, 6, 1,
1432+
4, 0, 5, 1, 3, 1, 12, 8, 3, 1, 11, 11,
1433+
9, 4, 12, 3, 12, 9, 11, 1, 7, 9, 7, 2,
1434+
];
1435+
let n = 12;
1436+
let mut v: VecDeque<_> = (0..n).collect();
1437+
let mut total_shift = 0;
1438+
for shift in shifts.iter().cloned() {
1439+
v.rotate_right(shift);
1440+
total_shift += shift;
1441+
for i in 0..n {
1442+
assert_eq!(v[(i + total_shift) % n], i);
1443+
}
1444+
}
1445+
}

0 commit comments

Comments
 (0)