Auto merge of #120050 - scottmcm:vec-resize-memset, r= · rust-lang/rust@0db48a7 (original) (raw)

4 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -2448,7 +2448,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
2448 2448 let len = self.len();
2449 2449
2450 2450 if new_len > len {
2451 -self.extend_with(new_len - len, value)
2451 +self.extend_trusted(core::iter::repeat_n(value, new_len - len));
2452 2452 } else {
2453 2453 self.truncate(new_len);
2454 2454 }
@@ -2562,38 +2562,6 @@ impl<T, A: Allocator, const N: usize> Vec<[T; N], A> {
2562 2562 }
2563 2563 }
2564 2564
2565 -impl<T: Clone, A: Allocator> Vec<T, A> {
2566 -#[cfg(not(no_global_oom_handling))]
2567 -/// Extend the vector by `n` clones of value.
2568 - fn extend_with(&mut self, n: usize, value: T) {
2569 -self.reserve(n);
2570 -
2571 -unsafe {
2572 -let mut ptr = self.as_mut_ptr().add(self.len());
2573 -// Use SetLenOnDrop to work around bug where compiler
2574 -// might not realize the store through `ptr` through self.set_len()
2575 -// don't alias.
2576 -let mut local_len = SetLenOnDrop::new(&mut self.len);
2577 -
2578 -// Write all elements except the last one
2579 -for _ in 1..n {
2580 - ptr::write(ptr, value.clone());
2581 - ptr = ptr.add(1);
2582 -// Increment the length in every step in case clone() panics
2583 - local_len.increment_len(1);
2584 -}
2585 -
2586 -if n > 0 {
2587 -// We can write the last element directly without cloning needlessly
2588 - ptr::write(ptr, value);
2589 - local_len.increment_len(1);
2590 -}
2591 -
2592 -// len set by scope guard
2593 -}
2594 -}
2595 -}
2596 -
2597 2565 impl<T: PartialEq, A: Allocator> Vec<T, A> {
2598 2566 /// Removes consecutive repeated elements in the vector according to the
2599 2567 /// [`PartialEq`] trait implementation.
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ pub(super) trait SpecFromElem: Sized {
13 13 impl<T: Clone> SpecFromElem for T {
14 14 default fn from_elem<A: Allocator>(elem: Self, n: usize, alloc: A) -> Vec<Self, A> {
15 15 let mut v = Vec::with_capacity_in(n, alloc);
16 - v.extend_with(n, elem);
16 + v.extend_trusted(core::iter::repeat_n(elem, n));
17 17 v
18 18 }
19 19 }
@@ -25,7 +25,7 @@ impl<T: Clone + IsZero> SpecFromElem for T {
25 25 return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
26 26 }
27 27 let mut v = Vec::with_capacity_in(n, alloc);
28 - v.extend_with(n, elem);
28 + v.extend_trusted(core::iter::repeat_n(elem, n));
29 29 v
30 30 }
31 31 }
Original file line number Diff line number Diff line change
@@ -110,6 +110,34 @@ impl Drop for RepeatN {
110 110 }
111 111 }
112 112
113 +trait SpecRepeatN<A> {
114 +unsafe fn spec_next_unchecked(&mut self) -> A;
115 +}
116 +
117 +impl<A: Clone> SpecRepeatN<A> for RepeatN<A> {
118 +default unsafe fn spec_next_unchecked(&mut self) -> A {
119 +self.count -= 1;
120 +
121 +if self.count == 0 {
122 +// SAFETY: we just lowered the count to zero so it won't be dropped
123 +// later, and thus it's okay to take it here.
124 +unsafe { ManuallyDrop::take(&mut self.element) }
125 +} else {
126 +A::clone(&self.element)
127 +}
128 +}
129 +}
130 +
131 +impl<A: Copy> SpecRepeatN<A> for RepeatN<A> {
132 +unsafe fn spec_next_unchecked(&mut self) -> A {
133 +self.count -= 1;
134 +
135 +// For `Copy` types, we can always just read the item directly,
136 +// so skip having a branch that would need to be optimized out.
137 +*self.element
138 +}
139 +}
140 +
113 141 #[unstable(feature = "iter_repeat_n", issue = "104434")]
114 142 impl<A: Clone> Iterator for RepeatN<A> {
115 143 type Item = A;
@@ -120,15 +148,8 @@ impl<A: Clone> Iterator for RepeatN {
120 148 return None;
121 149 }
122 150
123 -self.count -= 1;
124 -Some(if self.count == 0 {
125 -// SAFETY: the check above ensured that the count used to be non-zero,
126 -// so element hasn't been dropped yet, and we just lowered the count to
127 -// zero so it won't be dropped later, and thus it's okay to take it here.
128 -unsafe { ManuallyDrop::take(&mut self.element) }
129 -} else {
130 -A::clone(&self.element)
131 -})
151 +// SAFETY: Just confirmed above that the iterator is non-empty
152 +unsafe { Some(self.spec_next_unchecked()) }
132 153 }
133 154
134 155 #[inline]
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
1 +// compile-flags: -O
2 +// no-system-llvm
3 +// only-64bit
4 +// ignore-debug (the extra assertions get in the way)
5 +
6 +#![crate_type = "lib"]
7 +
8 +pub fn resize_with_bytes_is_one_memset(x: &mut Vec<u8>) {
9 +let new_len = x.len() + 456789;
10 + x.resize(new_len, 123);
11 +}
12 +
13 +// CHECK: call void @llvm.memset.p0.i64({{.+}}, i8 123, i64 456789, i1 false)