Skip to content

Commit 74054d7

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 5b150d2 + 28e44dc commit 74054d7

File tree

2 files changed

+44
-26
lines changed

2 files changed

+44
-26
lines changed

library/alloc/src/vec/mod.rs

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ use self::spec_extend::SpecExtend;
172172
#[cfg(not(no_global_oom_handling))]
173173
mod spec_extend;
174174

175+
#[cfg(not(no_global_oom_handling))]
176+
use self::spec_extend_with::SpecExtendWith;
177+
178+
#[cfg(not(no_global_oom_handling))]
179+
mod spec_extend_with;
180+
175181
/// A contiguous growable array type, written as `Vec<T>`, short for 'vector'.
176182
///
177183
/// # Examples
@@ -3498,34 +3504,11 @@ impl<T, A: Allocator, const N: usize> Vec<[T; N], A> {
34983504
}
34993505

35003506
impl<T: Clone, A: Allocator> Vec<T, A> {
3501-
#[cfg(not(no_global_oom_handling))]
35023507
/// Extend the vector by `n` clones of value.
3508+
#[cfg(not(no_global_oom_handling))]
3509+
#[inline]
35033510
fn extend_with(&mut self, n: usize, value: T) {
3504-
self.reserve(n);
3505-
3506-
unsafe {
3507-
let mut ptr = self.as_mut_ptr().add(self.len());
3508-
// Use SetLenOnDrop to work around bug where compiler
3509-
// might not realize the store through `ptr` through self.set_len()
3510-
// don't alias.
3511-
let mut local_len = SetLenOnDrop::new(&mut self.len);
3512-
3513-
// Write all elements except the last one
3514-
for _ in 1..n {
3515-
ptr::write(ptr, value.clone());
3516-
ptr = ptr.add(1);
3517-
// Increment the length in every step in case clone() panics
3518-
local_len.increment_len(1);
3519-
}
3520-
3521-
if n > 0 {
3522-
// We can write the last element directly without cloning needlessly
3523-
ptr::write(ptr, value);
3524-
local_len.increment_len(1);
3525-
}
3526-
3527-
// len set by scope guard
3528-
}
3511+
<Self as SpecExtendWith<T>>::spec_extend_with(self, n, value);
35293512
}
35303513
}
35313514

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use core::clone::TrivialClone;
2+
use core::{iter, ptr};
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+
fn spec_extend_with(&mut self, n: usize, value: T);
10+
}
11+
12+
impl<T: Clone, A: Allocator> SpecExtendWith<T> for Vec<T, A> {
13+
#[inline]
14+
default fn spec_extend_with(&mut self, n: usize, value: T) {
15+
self.extend_trusted(iter::repeat_n(value, n));
16+
}
17+
}
18+
19+
impl<T: TrivialClone, A: Allocator> SpecExtendWith<T> for Vec<T, A> {
20+
fn spec_extend_with(&mut self, n: usize, value: T) {
21+
let len = self.len();
22+
self.reserve(n);
23+
let unfilled = self.spare_capacity_mut().as_mut_ptr().cast_init();
24+
25+
for i in 0..n {
26+
// SAFETY: `unfilled` is at least as long as `n` thanks
27+
// to the `reserve` call. Because `T` is `TrivialClone`,
28+
// this is equivalent to calling `T::clone` for every element.
29+
unsafe { ptr::write(unfilled.add(i), ptr::read(&value)) };
30+
}
31+
32+
// SAFETY: the elements have been initialized above.
33+
unsafe { self.set_len(len + n) }
34+
}
35+
}

0 commit comments

Comments
 (0)