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) |