Skip to content

Commit 4f5a239

Browse files
Auto merge of #133662 - paolobarbolini:vec-extend-with-via-repeatn, r=<try>
Use `iter::repeat_n` to implement `Vec::extend_with`
2 parents 0dd07bd + bbcb772 commit 4f5a239

File tree

2 files changed

+43
-25
lines changed

2 files changed

+43
-25
lines changed

library/alloc/src/vec/mod.rs

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,12 @@ use self::spec_extend::SpecExtend;
150150
#[cfg(not(no_global_oom_handling))]
151151
mod spec_extend;
152152

153+
#[cfg(not(no_global_oom_handling))]
154+
use self::spec_extend_with::SpecExtendWith;
155+
156+
#[cfg(not(no_global_oom_handling))]
157+
mod spec_extend_with;
158+
153159
/// A contiguous growable array type, written as `Vec<T>`, short for 'vector'.
154160
///
155161
/// # Examples
@@ -3258,31 +3264,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
32583264
#[track_caller]
32593265
/// Extend the vector by `n` clones of value.
32603266
fn extend_with(&mut self, n: usize, value: T) {
3261-
self.reserve(n);
3262-
3263-
unsafe {
3264-
let mut ptr = self.as_mut_ptr().add(self.len());
3265-
// Use SetLenOnDrop to work around bug where compiler
3266-
// might not realize the store through `ptr` through self.set_len()
3267-
// don't alias.
3268-
let mut local_len = SetLenOnDrop::new(&mut self.len);
3269-
3270-
// Write all elements except the last one
3271-
for _ in 1..n {
3272-
ptr::write(ptr, value.clone());
3273-
ptr = ptr.add(1);
3274-
// Increment the length in every step in case clone() panics
3275-
local_len.increment_len(1);
3276-
}
3277-
3278-
if n > 0 {
3279-
// We can write the last element directly without cloning needlessly
3280-
ptr::write(ptr, value);
3281-
local_len.increment_len(1);
3282-
}
3283-
3284-
// len set by scope guard
3285-
}
3267+
<Self as SpecExtendWith<T>>::spec_extend_with(self, n, value);
32863268
}
32873269
}
32883270

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use core::iter;
2+
use core::mem::MaybeUninit;
3+
4+
use super::Vec;
5+
use crate::alloc::Allocator;
6+
7+
// Specialization trait used for Vec::extend_with
8+
pub(super) trait SpecExtendWith<T> {
9+
#[track_caller]
10+
fn spec_extend_with(&mut self, n: usize, value: T);
11+
}
12+
13+
impl<T: Clone, A: Allocator> SpecExtendWith<T> for Vec<T, A> {
14+
#[track_caller]
15+
default fn spec_extend_with(&mut self, n: usize, value: T) {
16+
self.extend_trusted(iter::repeat_n(value, n));
17+
}
18+
}
19+
20+
impl<T: Copy, A: Allocator> SpecExtendWith<T> for Vec<T, A> {
21+
#[track_caller]
22+
fn spec_extend_with(&mut self, n: usize, value: T) {
23+
let len = self.len();
24+
self.reserve(n);
25+
let unfilled = self.spare_capacity_mut();
26+
27+
// SAFETY: the above `reserve` call guarantees `n` to be in bounds.
28+
let unfilled = unsafe { unfilled.get_unchecked_mut(..n) };
29+
for elem in unfilled {
30+
*elem = MaybeUninit::new(value);
31+
}
32+
33+
// SAFETY: the elements have been initialized above.
34+
unsafe { self.set_len(len + n) }
35+
}
36+
}

0 commit comments

Comments
 (0)