Skip to content

Commit 968ae7b

Browse files
committed
Auto merge of #41191 - seanmonstar:spec-extend-vec-intoiter, r=alexcrichton
specialize Extend for Vec with IntoIter Before, `vec.extend(&other_vec)` was quite a bit faster than `vec.extend(other_vec)`. This allows extending by consuming a vec to use the same code as extending from a slice.
2 parents fa6b50f + f85a533 commit 968ae7b

File tree

2 files changed

+41
-8
lines changed

2 files changed

+41
-8
lines changed

src/libcollections/tests/vec.rs

+22
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ fn test_extend() {
8484
let mut v = Vec::new();
8585
let mut w = Vec::new();
8686

87+
v.extend(w.clone());
88+
assert_eq!(v, &[]);
89+
8790
v.extend(0..3);
8891
for i in 0..3 {
8992
w.push(i)
@@ -100,6 +103,25 @@ fn test_extend() {
100103

101104
v.extend(w.clone()); // specializes to `append`
102105
assert!(v.iter().eq(w.iter().chain(w.iter())));
106+
107+
// Zero sized types
108+
#[derive(PartialEq, Debug)]
109+
struct Foo;
110+
111+
let mut a = Vec::new();
112+
let b = vec![Foo, Foo];
113+
114+
a.extend(b);
115+
assert_eq!(a, &[Foo, Foo]);
116+
117+
// Double drop
118+
let mut count_x = 0;
119+
{
120+
let mut x = Vec::new();
121+
let y = vec![DropCounter { count: &mut count_x }];
122+
x.extend(y);
123+
}
124+
assert_eq!(count_x, 1);
103125
}
104126

105127
#[test]

src/libcollections/vec.rs

+19-8
Original file line numberDiff line numberDiff line change
@@ -1041,18 +1041,22 @@ impl<T> Vec<T> {
10411041
#[inline]
10421042
#[stable(feature = "append", since = "1.4.0")]
10431043
pub fn append(&mut self, other: &mut Self) {
1044-
self.reserve(other.len());
1045-
let len = self.len();
1046-
unsafe {
1047-
ptr::copy_nonoverlapping(other.as_ptr(), self.get_unchecked_mut(len), other.len());
1048-
}
1049-
1050-
self.len += other.len();
10511044
unsafe {
1045+
self.append_elements(other.as_slice() as _);
10521046
other.set_len(0);
10531047
}
10541048
}
10551049

1050+
/// Appends elements to `Self` from other buffer.
1051+
#[inline]
1052+
unsafe fn append_elements(&mut self, other: *const [T]) {
1053+
let count = (*other).len();
1054+
self.reserve(count);
1055+
let len = self.len();
1056+
ptr::copy_nonoverlapping(other as *const T, self.get_unchecked_mut(len), count);
1057+
self.len += count;
1058+
}
1059+
10561060
/// Create a draining iterator that removes the specified range in the vector
10571061
/// and yields the removed items.
10581062
///
@@ -1738,7 +1742,7 @@ impl<T, I> SpecExtend<T, I> for Vec<T>
17381742
vector
17391743
}
17401744

1741-
fn spec_extend(&mut self, iterator: I) {
1745+
default fn spec_extend(&mut self, iterator: I) {
17421746
// This is the case for a TrustedLen iterator.
17431747
let (low, high) = iterator.size_hint();
17441748
if let Some(high_value) = high {
@@ -1783,6 +1787,13 @@ impl<T> SpecExtend<T, IntoIter<T>> for Vec<T> {
17831787
vector
17841788
}
17851789
}
1790+
1791+
fn spec_extend(&mut self, mut iterator: IntoIter<T>) {
1792+
unsafe {
1793+
self.append_elements(iterator.as_slice() as _);
1794+
}
1795+
iterator.ptr = iterator.end;
1796+
}
17861797
}
17871798

17881799
impl<'a, T: 'a, I> SpecExtend<&'a T, I> for Vec<T>

0 commit comments

Comments
 (0)