Skip to content

Commit a3ebd87

Browse files
committed
add comments and make tests easier to read
1 parent df40899 commit a3ebd87

File tree

2 files changed

+113
-62
lines changed

2 files changed

+113
-62
lines changed

library/alloc/src/collections/vec_deque/mod.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ impl<T, A: Allocator> VecDeque<T, A> {
266266
let src_wraps = room_after_src < count;
267267
let dst_wraps = room_after_dst < count;
268268

269+
// Wrapping occurs if `capacity` is contained within `wrapped_src..wrapped_src + count` or `wrapped_dst..wrapped_dst + count`.
270+
// Since these two ranges must not overlap as per the safety invariants of this function, only one range can wrap.
269271
debug_assert!(
270272
!(src_wraps && dst_wraps),
271273
"BUG: at most one of src and dst can wrap. src={src} dst={dst} count={count} cap={}",
@@ -3150,6 +3152,10 @@ impl<T: Clone, A: Allocator> SpecExtendFromWithin for VecDeque<T, A> {
31503152
// - Ranges do not overlap: src entirely spans initialized values, dst entirely spans uninitialized values.
31513153
// - Ranges are in bounds: guaranteed by the caller.
31523154
let ranges = self.nonoverlapping_ranges(src, dst, count, self.head);
3155+
3156+
// `len` is updated after every clone to prevent leaking and
3157+
// leave the deque in the right state when a clone implementation panics
3158+
31533159
for (src, dst, count) in ranges {
31543160
for offset in 0..count {
31553161
dst.add(offset).write((*src.add(offset)).clone());
@@ -3172,23 +3178,33 @@ impl<T: Clone, A: Allocator> SpecExtendFromWithin for VecDeque<T, A> {
31723178
// - Ranges do not overlap: src entirely spans initialized values, dst entirely spans uninitialized values.
31733179
// - Ranges are in bounds: guaranteed by the caller.
31743180
let ranges = self.nonoverlapping_ranges(src, dst, count, new_head);
3181+
3182+
// Cloning is done in reverse because we prepend to the front of the deque,
3183+
// we can't get holes in the *logical* buffer.
3184+
// `head` and `len` are updated after every clone to prevent leaking and
3185+
// leave the deque in the right state when a clone implementation panics
3186+
3187+
// Clone the first range
31753188
let (src, dst, count) = ranges[1];
31763189
for offset in (0..count).rev() {
31773190
dst.add(offset).write((*src.add(offset)).clone());
31783191
self.head -= 1;
31793192
self.len += 1;
31803193
}
31813194

3195+
// Clone the second range
31823196
let (src, dst, count) = ranges[0];
31833197
let mut iter = (0..count).rev();
31843198
if let Some(offset) = iter.next() {
31853199
dst.add(offset).write((*src.add(offset)).clone());
3200+
// After the first clone of the second range, wrap `head` around
31863201
if self.head == 0 {
31873202
self.head = cap;
31883203
}
31893204
self.head -= 1;
31903205
self.len += 1;
31913206

3207+
// Continue like normal
31923208
for offset in iter {
31933209
dst.add(offset).write((*src.add(offset)).clone());
31943210
self.head -= 1;

library/alloctests/tests/vec_deque.rs

Lines changed: 97 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,77 +1856,99 @@ fn test_extend_from_within() {
18561856
let mut v = VecDeque::with_capacity(8);
18571857
v.extend(0..6);
18581858
v.truncate_front(4);
1859+
assert_eq!(v, [2, 3, 4, 5]);
18591860
v.extend_from_within(1..4);
1861+
assert_eq!(v, [2, 3, 4, 5, 3, 4, 5]);
1862+
// check it really wrapped
18601863
assert_eq!(v.as_slices(), ([2, 3, 4, 5, 3, 4].as_slice(), [5].as_slice()));
18611864
v.extend_from_within(1..=2);
18621865
assert_eq!(v, [2, 3, 4, 5, 3, 4, 5, 3, 4]);
18631866
v.extend_from_within(..3);
18641867
assert_eq!(v, [2, 3, 4, 5, 3, 4, 5, 3, 4, 2, 3, 4]);
18651868
}
18661869

1870+
/// Struct that allows tracking clone and drop calls and can be set to panic on calling clone.
18671871
struct CloneTracker<'a> {
1868-
clone: &'a Cell<u32>,
1869-
drop: &'a Cell<u32>,
1872+
id: usize,
1873+
// Counters can be set to None if not needed.
1874+
clone: Option<&'a Cell<u32>>,
1875+
drop: Option<&'a Cell<u32>>,
18701876
panic: bool,
18711877
}
18721878

1879+
impl<'a> CloneTracker<'a> {
1880+
pub const DUMMY: Self = Self { id: 999, clone: None, drop: None, panic: false };
1881+
}
1882+
18731883
impl<'a> Clone for CloneTracker<'a> {
18741884
fn clone(&self) -> Self {
1875-
self.clone.set(self.clone.get() + 1);
18761885
if self.panic {
18771886
panic!();
18781887
}
1879-
Self { clone: self.clone, drop: self.drop, panic: false }
1888+
1889+
if let Some(clone_count) = self.clone {
1890+
clone_count.update(|c| c + 1);
1891+
}
1892+
1893+
Self { id: self.id, clone: self.clone, drop: self.drop, panic: false }
18801894
}
18811895
}
18821896

18831897
impl<'a> Drop for CloneTracker<'a> {
18841898
fn drop(&mut self) {
1885-
self.drop.set(self.drop.get() + 1);
1899+
if let Some(drop_count) = self.drop {
1900+
drop_count.update(|c| c + 1);
1901+
}
18861902
}
18871903
}
18881904

18891905
#[test]
18901906
fn test_extend_from_within_clone() {
1891-
let clone_counts = [const { Cell::new(0) }; 6];
1892-
let drop_count = Cell::new(0);
1907+
let clone_counts = [const { Cell::new(0) }; 4];
18931908
let mut v = VecDeque::with_capacity(10);
1894-
v.extend(clone_counts.iter().map(|clone_count| CloneTracker {
1895-
clone: clone_count,
1896-
drop: &drop_count,
1909+
// insert 2 dummy elements to have the buffer wrap later
1910+
v.extend([CloneTracker::DUMMY; 2]);
1911+
v.extend(clone_counts.iter().enumerate().map(|(id, clone_count)| CloneTracker {
1912+
id,
1913+
clone: Some(clone_count),
1914+
drop: None,
18971915
panic: false,
18981916
}));
1917+
// remove the dummy elements
18991918
v.truncate_front(4);
1919+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [0, 1, 2, 3]);
19001920

19011921
v.extend_from_within(2..);
1922+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [0, 1, 2, 3, 2, 3]);
1923+
// elements at index 2 and 3 should have been cloned once
1924+
assert_eq!(clone_counts.each_ref().map(Cell::get), [0, 0, 1, 1]);
1925+
// it is important that the deque wraps because of this operation, we want to test if wrapping is handled correctly
19021926
v.extend_from_within(1..5);
1903-
assert_eq!(
1904-
v.iter().map(|tr| tr.clone.get()).collect::<Vec<_>>(),
1905-
[0, 1, 3, 2, 3, 2, 1, 3, 2, 3],
1906-
);
1907-
assert_eq!(
1908-
clone_counts.each_ref().map(|c| {
1909-
let old = c.get();
1910-
c.set(0);
1911-
old
1912-
}),
1913-
[0, 0, 0, 1, 3, 2],
1914-
);
1927+
// total length is 10, 8 in the first part and 2 in the second part
1928+
assert_eq!(v.as_slices().0.len(), 8);
1929+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [0, 1, 2, 3, 2, 3, 1, 2, 3, 2]);
1930+
// the new elements are from indices 1, 2, 3 and 2, those elements should have their clone count
1931+
// incremented (clone count at index 2 gets incremented twice so ends up at 3)
1932+
assert_eq!(clone_counts.each_ref().map(Cell::get), [0, 1, 3, 2]);
19151933
}
19161934

19171935
#[test]
19181936
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
19191937
fn test_extend_from_within_clone_panic() {
1920-
let clone_counts = [const { Cell::new(0) }; 6];
1938+
let clone_counts = [const { Cell::new(0) }; 4];
19211939
let drop_count = Cell::new(0);
19221940
let mut v = VecDeque::with_capacity(8);
1923-
v.extend(clone_counts.iter().map(|clone_count| CloneTracker {
1924-
clone: clone_count,
1925-
drop: &drop_count,
1941+
// insert 2 dummy elements to have the buffer wrap later
1942+
v.extend([CloneTracker::DUMMY; 2]);
1943+
v.extend(clone_counts.iter().enumerate().map(|(id, clone_count)| CloneTracker {
1944+
id,
1945+
clone: Some(clone_count),
1946+
drop: Some(&drop_count),
19261947
panic: false,
19271948
}));
1928-
1949+
// remove the dummy elements
19291950
v.truncate_front(4);
1951+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [0, 1, 2, 3]);
19301952

19311953
// panic after wrapping
19321954
v[2].panic = true;
@@ -1935,11 +1957,15 @@ fn test_extend_from_within_clone_panic() {
19351957
}))
19361958
.unwrap_err();
19371959
v[2].panic = false;
1938-
assert_eq!(v.iter().map(|tr| tr.clone.get()).collect::<Vec<_>>(), [1, 1, 1, 0, 1, 1]);
1939-
assert_eq!(clone_counts.each_ref().map(|c| c.get()), [0, 0, 1, 1, 1, 0]);
1940-
assert_eq!(drop_count.get(), 2);
1960+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [0, 1, 2, 3, 0, 1]);
1961+
// the first 2 elements were cloned
1962+
assert_eq!(clone_counts.each_ref().map(Cell::get), [1, 1, 0, 0]);
1963+
// nothing should have been dropped
1964+
assert_eq!(drop_count.get(), 0);
19411965

19421966
v.truncate_front(2);
1967+
assert_eq!(drop_count.get(), 4);
1968+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [0, 1]);
19431969

19441970
// panic before wrapping
19451971
v[1].panic = true;
@@ -1948,9 +1974,11 @@ fn test_extend_from_within_clone_panic() {
19481974
}))
19491975
.unwrap_err();
19501976
v[1].panic = false;
1951-
assert_eq!(v.iter().map(|tr| tr.clone.get()).collect::<Vec<_>>(), [2, 2, 2]);
1952-
assert_eq!(clone_counts.each_ref().map(|c| c.get()), [0, 0, 2, 2, 1, 0]);
1953-
assert_eq!(drop_count.get(), 6);
1977+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [0, 1, 0]);
1978+
// only the first element was cloned
1979+
assert_eq!(clone_counts.each_ref().map(Cell::get), [2, 1, 0, 0]);
1980+
// nothing more should have been dropped
1981+
assert_eq!(drop_count.get(), 4);
19541982
}
19551983

19561984
#[test]
@@ -1968,45 +1996,46 @@ fn test_prepend_from_within() {
19681996

19691997
#[test]
19701998
fn test_prepend_from_within_clone() {
1971-
let clone_counts = [const { Cell::new(0) }; 6];
1972-
let drop_count = Cell::new(0);
1999+
let clone_counts = [const { Cell::new(0) }; 4];
2000+
// insert 2 dummy elements to have the buffer wrap later
19732001
let mut v = VecDeque::with_capacity(10);
1974-
v.extend(clone_counts.iter().map(|clone_count| CloneTracker {
1975-
clone: clone_count,
1976-
drop: &drop_count,
2002+
v.extend([CloneTracker::DUMMY; 2]);
2003+
v.extend(clone_counts.iter().enumerate().map(|(id, clone_count)| CloneTracker {
2004+
id,
2005+
clone: Some(clone_count),
2006+
drop: None,
19772007
panic: false,
19782008
}));
2009+
// remove the dummy elements
19792010
v.truncate_front(4);
2011+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [0, 1, 2, 3]);
19802012

19812013
v.prepend_from_within(..2);
2014+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [0, 1, 0, 1, 2, 3]);
19822015
v.prepend_from_within(1..5);
1983-
assert_eq!(
1984-
v.iter().map(|tr| tr.clone.get()).collect::<Vec<_>>(),
1985-
[3, 2, 3, 1, 2, 3, 2, 3, 1, 0],
1986-
);
1987-
assert_eq!(
1988-
clone_counts.each_ref().map(|c| {
1989-
let old = c.get();
1990-
c.set(0);
1991-
old
1992-
}),
1993-
[0, 0, 2, 3, 1, 0],
1994-
);
2016+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [1, 0, 1, 2, 0, 1, 0, 1, 2, 3]);
2017+
// count the number of each element and subtract one (clone should have been called n-1 times if we have n elements)
2018+
// example: 0 appears 3 times so should have been cloned twice, 1 appears 4 times so cloned 3 times, etc
2019+
assert_eq!(clone_counts.each_ref().map(Cell::get), [2, 3, 1, 0]);
19952020
}
19962021

19972022
#[test]
19982023
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
19992024
fn test_prepend_from_within_clone_panic() {
2000-
let clone_counts = [const { Cell::new(0) }; 6];
2025+
let clone_counts = [const { Cell::new(0) }; 4];
20012026
let drop_count = Cell::new(0);
20022027
let mut v = VecDeque::with_capacity(8);
2003-
v.extend(clone_counts.iter().map(|clone_count| CloneTracker {
2004-
clone: clone_count,
2005-
drop: &drop_count,
2028+
// insert 2 dummy elements to have the buffer wrap later
2029+
v.extend([CloneTracker::DUMMY; 2]);
2030+
v.extend(clone_counts.iter().enumerate().map(|(id, clone_count)| CloneTracker {
2031+
id,
2032+
clone: Some(clone_count),
2033+
drop: Some(&drop_count),
20062034
panic: false,
20072035
}));
2008-
2036+
// remove the dummy elements
20092037
v.truncate_front(4);
2038+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [0, 1, 2, 3]);
20102039

20112040
// panic after wrapping
20122041
v[1].panic = true;
@@ -2015,11 +2044,15 @@ fn test_prepend_from_within_clone_panic() {
20152044
}))
20162045
.unwrap_err();
20172046
v[1].panic = false;
2018-
assert_eq!(v.iter().map(|tr| tr.clone.get()).collect::<Vec<_>>(), [1, 1, 0, 1, 1, 1]);
2019-
assert_eq!(clone_counts.each_ref().map(|c| c.get()), [0, 0, 0, 1, 1, 1]);
2020-
assert_eq!(drop_count.get(), 2);
2047+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [2, 3, 0, 1, 2, 3]);
2048+
// the last 2 elements were cloned
2049+
assert_eq!(clone_counts.each_ref().map(Cell::get), [0, 0, 1, 1]);
2050+
// nothing should have been dropped
2051+
assert_eq!(drop_count.get(), 0);
20212052

20222053
v.truncate_front(2);
2054+
assert_eq!(drop_count.get(), 4);
2055+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [2, 3]);
20232056

20242057
// panic before wrapping
20252058
v[0].panic = true;
@@ -2028,9 +2061,11 @@ fn test_prepend_from_within_clone_panic() {
20282061
}))
20292062
.unwrap_err();
20302063
v[0].panic = false;
2031-
assert_eq!(v.iter().map(|tr| tr.clone.get()).collect::<Vec<_>>(), [2, 2, 2]);
2032-
assert_eq!(clone_counts.each_ref().map(|c| c.get()), [0, 0, 0, 1, 2, 2]);
2033-
assert_eq!(drop_count.get(), 6);
2064+
assert_eq!(v.iter().map(|tr| tr.id).collect::<Vec<_>>(), [3, 2, 3]);
2065+
// only the first element was cloned
2066+
assert_eq!(clone_counts.each_ref().map(Cell::get), [0, 0, 1, 2]);
2067+
// nothing more should have been dropped
2068+
assert_eq!(drop_count.get(), 4);
20342069
}
20352070

20362071
#[test]
@@ -2041,7 +2076,7 @@ fn test_extend_and_prepend_from_within() {
20412076
v.prepend_from_within(..2);
20422077
assert_eq!(v.iter().map(|s| &**s).collect::<String>(), "56567899");
20432078
v.clear();
2044-
v.extend(['1', '2', '3'].into_iter().map(String::from));
2079+
v.extend(['1', '2', '3'].map(String::from));
20452080
v.prepend_from_within(..);
20462081
v.extend_from_within(..);
20472082
assert_eq!(v.iter().map(|s| &**s).collect::<String>(), "123123123123");

0 commit comments

Comments
 (0)