Skip to content

Commit 24bc854

Browse files
committed
Non-naive implementation for VecDeque.append
1 parent 9d6f4e5 commit 24bc854

File tree

2 files changed

+192
-2
lines changed

2 files changed

+192
-2
lines changed

src/liballoc/collections/vec_deque.rs

Lines changed: 138 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1834,8 +1834,144 @@ impl<T> VecDeque<T> {
18341834
#[inline]
18351835
#[stable(feature = "append", since = "1.4.0")]
18361836
pub fn append(&mut self, other: &mut Self) {
1837-
// naive impl
1838-
self.extend(other.drain(..));
1837+
// Copy from src[i1..i1 + len] to dst[i2..i2 + len].
1838+
// Does not check if the ranges are valid.
1839+
unsafe fn copy_part<T>(i1: usize, i2: usize, len: usize, src: &[T], dst: &mut [T]) {
1840+
debug_assert!(src.get(i1..i1 + len).is_some() && dst.get(i2..i2 + len).is_some());
1841+
ptr::copy_nonoverlapping(src.as_ptr().add(i1), dst.as_mut_ptr().add(i2), len);
1842+
}
1843+
1844+
let src_total = other.len();
1845+
1846+
// Guarantees there is space in `self` for `other`.
1847+
self.reserve(src_total);
1848+
1849+
self.head = {
1850+
let dst_start_1 = self.head;
1851+
let src_start_1 = other.tail;
1852+
let dst_wrap_point = self.cap();
1853+
let src_wrap_point = other.cap();
1854+
1855+
let dst = unsafe { self.buffer_as_mut_slice() };
1856+
let src = unsafe { other.buffer_as_slice() };
1857+
1858+
let src_wraps = other.tail > other.head;
1859+
let dst_wraps = dst_start_1 + src_total > dst_wrap_point;
1860+
1861+
// When minimizing the amount of calls to `copy_part`, there are
1862+
// 6 different cases to handle. Whether src and/or dst wrap are 4
1863+
// combinations and there are 3 distinct cases when they both wrap.
1864+
// 6 = 3 + 1 + 1 + 1
1865+
match (src_wraps, dst_wraps) {
1866+
(true, true) => {
1867+
let dst_before_wrap = dst_wrap_point - dst_start_1;
1868+
let src_before_wrap = src_wrap_point - src_start_1;
1869+
1870+
if src_before_wrap < dst_before_wrap {
1871+
// src
1872+
// [o o o . . . . . . o o o]
1873+
// 2 3 3 1 1 1
1874+
//
1875+
// dst
1876+
// [. . . . . . o o . . . .]
1877+
// 3 3 H 1 1 1 2
1878+
let src_2 = dst_before_wrap - src_before_wrap;
1879+
let dst_start_2 = dst_start_1 + src_before_wrap;
1880+
let src_3 = src_total - dst_before_wrap;
1881+
1882+
unsafe {
1883+
copy_part(src_start_1, dst_start_1, src_before_wrap, src, dst);
1884+
copy_part(0, dst_start_2, src_2, src, dst);
1885+
copy_part(src_2, 0, src_3, src, dst);
1886+
}
1887+
src_3
1888+
} else if src_before_wrap > dst_before_wrap {
1889+
// src
1890+
// [o o o . . . . . o o o o]
1891+
// 3 3 3 1 1 2 2
1892+
//
1893+
// dst
1894+
// [. . . . . . o o o o . .]
1895+
// 2 2 3 3 3 H 1 1
1896+
let src_2 = src_before_wrap - dst_before_wrap;
1897+
let src_start_2 = src_start_1 + dst_before_wrap;
1898+
let src_3 = src_total - src_before_wrap;
1899+
1900+
unsafe {
1901+
copy_part(src_start_1, dst_start_1, dst_before_wrap, src, dst);
1902+
copy_part(src_start_2, 0, src_2, src, dst);
1903+
copy_part(0, src_2, src_3, src, dst);
1904+
}
1905+
src_2 + src_3
1906+
} else {
1907+
// src
1908+
// [o o . . . . . . . o o o]
1909+
// 2 2 1 1 1
1910+
//
1911+
// dst
1912+
// [. . . . . . . o o . . .]
1913+
// 2 2 H 1 1 1
1914+
let src_2 = src_total - src_before_wrap;
1915+
1916+
unsafe {
1917+
copy_part(src_start_1, dst_start_1, src_before_wrap, src, dst);
1918+
copy_part(0, 0, src_2, src, dst);
1919+
}
1920+
src_2
1921+
}
1922+
}
1923+
(false, true) => {
1924+
// src
1925+
// [. . . o o o o o . . . .]
1926+
// 1 1 2 2 2
1927+
//
1928+
// dst
1929+
// [. . . . . . . o o o . .]
1930+
// 2 2 2 H 1 1
1931+
let dst_1 = dst_wrap_point - dst_start_1;
1932+
let src_start_2 = src_start_1 + dst_1;
1933+
let dst_2 = src_total - dst_1;
1934+
1935+
unsafe {
1936+
copy_part(src_start_1, dst_start_1, dst_1, src, dst);
1937+
copy_part(src_start_2, 0, dst_2, src, dst);
1938+
}
1939+
dst_2
1940+
}
1941+
(true, false) => {
1942+
// src
1943+
// [o o . . . . . . . o o o]
1944+
// 2 2 1 1 1
1945+
//
1946+
// dst
1947+
// [. o o . . . . . . . . .]
1948+
// 1 1 1 2 2 H
1949+
let src_1 = src_wrap_point - src_start_1;
1950+
let dst_start_2 = dst_start_1 + src_1;
1951+
let src_2 = src_total - src_1;
1952+
1953+
unsafe {
1954+
copy_part(src_start_1, dst_start_1, src_1, src, dst);
1955+
copy_part(0, dst_start_2, src_2, src, dst);
1956+
}
1957+
dst_start_1 + src_1 + src_2
1958+
}
1959+
(false, false) => {
1960+
// src
1961+
// [. . . o o o . . . . . .]
1962+
// 1 1 1
1963+
//
1964+
// dst
1965+
// [. o o o o o . . . . . .]
1966+
// 1 1 1 H
1967+
unsafe {
1968+
copy_part(src_start_1, dst_start_1, src_total, src, dst);
1969+
}
1970+
dst_start_1 + src_total
1971+
}
1972+
}
1973+
};
1974+
other.clear();
18391975
}
18401976

18411977
/// Retains only the elements specified by the predicate.

src/liballoc/tests/vec_deque.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,60 @@ fn test_append() {
928928
assert_eq!(a.iter().cloned().collect::<Vec<_>>(), []);
929929
}
930930

931+
#[test]
932+
fn test_append_advanced() {
933+
fn check(
934+
a_push_back: usize,
935+
a_pop_back: usize,
936+
b_push_back: usize,
937+
b_pop_back: usize,
938+
a_push_front: usize,
939+
a_pop_front: usize,
940+
b_push_front: usize,
941+
b_pop_front: usize
942+
) {
943+
let mut taken = 0;
944+
let mut a = VecDeque::new();
945+
let mut b = VecDeque::new();
946+
for n in (taken..).take(a_push_back) {
947+
a.push_back(n);
948+
}
949+
taken += a_push_back;
950+
for n in (taken..).take(a_push_front) {
951+
a.push_front(n);
952+
}
953+
taken += a_push_front;
954+
for n in (taken..).take(b_push_back) {
955+
b.push_back(n);
956+
}
957+
taken += b_push_back;
958+
for n in (taken..).take(b_push_front) {
959+
b.push_front(n);
960+
}
961+
962+
a.drain(..a_pop_back);
963+
a.drain(a_pop_front..);
964+
b.drain(..b_pop_back);
965+
b.drain(b_pop_front..);
966+
let checked = a.iter().chain(b.iter()).map(|&x| x).collect::<Vec<usize>>();
967+
a.append(&mut b);
968+
assert_eq!(a, checked);
969+
assert!(b.is_empty());
970+
}
971+
for a_push in 0..17 {
972+
for a_pop in 0..a_push {
973+
for b_push in 0..17 {
974+
for b_pop in 0..b_push {
975+
check(a_push, a_pop, b_push, b_pop, 0, 0, 0, 0);
976+
check(a_push, a_pop, b_push, b_pop, a_push, 0, 0, 0);
977+
check(a_push, a_pop, b_push, b_pop, 0, 0, b_push, 0);
978+
check(0, 0, 0, 0, a_push, a_pop, b_push, b_pop);
979+
}
980+
}
981+
}
982+
}
983+
}
984+
931985
#[test]
932986
fn test_retain() {
933987
let mut buf = VecDeque::new();

0 commit comments

Comments
 (0)