From 48206290c5d92112dfa8f138abb7c501fcc03769 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 18 Nov 2022 21:17:13 -0800 Subject: [PATCH] Use normal iterators instead of the internal `vec::ExtendWith` Repeating is `TrustedLen`, so we don't need another copy of [the `TrustedLen` specialization for `extend`](https://github.com/rust-lang/rust/blob/c5d82ed7a4ad94a538bb87e5016e7d5ce0bd434b/library/alloc/src/vec/spec_extend.rs#L27). (This is a simpler version of #104596, which tried to do too many things at once.) --- library/alloc/src/vec/mod.rs | 62 +------------------------ library/alloc/src/vec/spec_from_elem.rs | 7 +-- src/test/codegen/vec-calloc.rs | 27 +++++++++-- 3 files changed, 28 insertions(+), 68 deletions(-) diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 766006939fa48..69a107440c20a 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2163,7 +2163,7 @@ impl Vec { { let len = self.len(); if new_len > len { - self.extend_with(new_len - len, ExtendFunc(f)); + self.extend(iter::repeat_with(f).take(new_len - len)); } else { self.truncate(new_len); } @@ -2361,7 +2361,7 @@ impl Vec { let len = self.len(); if new_len > len { - self.extend_with(new_len - len, ExtendElement(value)) + self.extend(iter::repeat_n(value, new_len - len)) } else { self.truncate(new_len); } @@ -2475,64 +2475,6 @@ impl Vec<[T; N], A> { } } -// This code generalizes `extend_with_{element,default}`. -trait ExtendWith { - fn next(&mut self) -> T; - fn last(self) -> T; -} - -struct ExtendElement(T); -impl ExtendWith for ExtendElement { - fn next(&mut self) -> T { - self.0.clone() - } - fn last(self) -> T { - self.0 - } -} - -struct ExtendFunc(F); -impl T> ExtendWith for ExtendFunc { - fn next(&mut self) -> T { - (self.0)() - } - fn last(mut self) -> T { - (self.0)() - } -} - -impl Vec { - #[cfg(not(no_global_oom_handling))] - /// Extend the vector by `n` values, using the given generator. - fn extend_with>(&mut self, n: usize, mut value: E) { - self.reserve(n); - - unsafe { - let mut ptr = self.as_mut_ptr().add(self.len()); - // Use SetLenOnDrop to work around bug where compiler - // might not realize the store through `ptr` through self.set_len() - // don't alias. - let mut local_len = SetLenOnDrop::new(&mut self.len); - - // Write all elements except the last one - for _ in 1..n { - ptr::write(ptr, value.next()); - ptr = ptr.add(1); - // Increment the length in every step in case next() panics - local_len.increment_len(1); - } - - if n > 0 { - // We can write the last element directly without cloning needlessly - ptr::write(ptr, value.last()); - local_len.increment_len(1); - } - - // len set by scope guard - } - } -} - impl Vec { /// Removes consecutive repeated elements in the vector according to the /// [`PartialEq`] trait implementation. diff --git a/library/alloc/src/vec/spec_from_elem.rs b/library/alloc/src/vec/spec_from_elem.rs index ff364c033ee98..c8ce9d9a691ec 100644 --- a/library/alloc/src/vec/spec_from_elem.rs +++ b/library/alloc/src/vec/spec_from_elem.rs @@ -1,9 +1,10 @@ +use core::iter; use core::ptr; use crate::alloc::Allocator; use crate::raw_vec::RawVec; -use super::{ExtendElement, IsZero, Vec}; +use super::{IsZero, Vec}; // Specialization trait used for Vec::from_elem pub(super) trait SpecFromElem: Sized { @@ -13,7 +14,7 @@ pub(super) trait SpecFromElem: Sized { impl SpecFromElem for T { default fn from_elem(elem: Self, n: usize, alloc: A) -> Vec { let mut v = Vec::with_capacity_in(n, alloc); - v.extend_with(n, ExtendElement(elem)); + v.extend(iter::repeat_n(elem, n)); v } } @@ -25,7 +26,7 @@ impl SpecFromElem for T { return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n }; } let mut v = Vec::with_capacity_in(n, alloc); - v.extend_with(n, ExtendElement(elem)); + v.extend(iter::repeat_n(elem, n)); v } } diff --git a/src/test/codegen/vec-calloc.rs b/src/test/codegen/vec-calloc.rs index ae6e448f172f7..7fd350dc0f45d 100644 --- a/src/test/codegen/vec-calloc.rs +++ b/src/test/codegen/vec-calloc.rs @@ -6,6 +6,7 @@ #![crate_type = "lib"] // CHECK-LABEL: @vec_zero_bytes +// CHECK-SAME: i64 %n #[no_mangle] pub fn vec_zero_bytes(n: usize) -> Vec { // CHECK-NOT: call {{.*}}alloc::vec::from_elem @@ -13,7 +14,7 @@ pub fn vec_zero_bytes(n: usize) -> Vec { // CHECK-NOT: call {{.*}}__rust_alloc( // CHECK-NOT: call {{.*}}llvm.memset - // CHECK: call {{.*}}__rust_alloc_zeroed( + // CHECK: call {{.*}}__rust_alloc_zeroed(i64 %n // CHECK-NOT: call {{.*}}alloc::vec::from_elem // CHECK-NOT: call {{.*}}reserve @@ -22,17 +23,19 @@ pub fn vec_zero_bytes(n: usize) -> Vec { // CHECK: ret void vec![0; n] -} +} // CHECK-LABEL: @vec_one_bytes +// CHECK-SAME: i64 %n #[no_mangle] pub fn vec_one_bytes(n: usize) -> Vec { // CHECK-NOT: call {{.*}}alloc::vec::from_elem // CHECK-NOT: call {{.*}}reserve // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - // CHECK: call {{.*}}__rust_alloc( + // CHECK: call {{.*}}__rust_alloc(i64 %n // CHECK: call {{.*}}llvm.memset + // CHECK-SAME: i8 1, i64 %n // CHECK-NOT: call {{.*}}alloc::vec::from_elem // CHECK-NOT: call {{.*}}reserve @@ -43,13 +46,20 @@ pub fn vec_one_bytes(n: usize) -> Vec { } // CHECK-LABEL: @vec_zero_scalar +// CHECK-SAME: i64 %n #[no_mangle] pub fn vec_zero_scalar(n: usize) -> Vec { // CHECK-NOT: call {{.*}}alloc::vec::from_elem // CHECK-NOT: call {{.*}}reserve // CHECK-NOT: call {{.*}}__rust_alloc( - // CHECK: call {{.*}}__rust_alloc_zeroed( + // CHECK: %[[BYTES:.+]] = shl i64 %n, 2 + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc( + + // CHECK: call {{.*}}__rust_alloc_zeroed(i64 %[[BYTES]] // CHECK-NOT: call {{.*}}alloc::vec::from_elem // CHECK-NOT: call {{.*}}reserve @@ -60,13 +70,20 @@ pub fn vec_zero_scalar(n: usize) -> Vec { } // CHECK-LABEL: @vec_one_scalar +// CHECK-SAME: i64 %n #[no_mangle] pub fn vec_one_scalar(n: usize) -> Vec { // CHECK-NOT: call {{.*}}alloc::vec::from_elem // CHECK-NOT: call {{.*}}reserve // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( - // CHECK: call {{.*}}__rust_alloc( + // CHECK: %[[BYTES:.+]] = shl i64 %n, 2 + + // CHECK-NOT: call {{.*}}alloc::vec::from_elem + // CHECK-NOT: call {{.*}}reserve + // CHECK-NOT: call {{.*}}__rust_alloc_zeroed( + + // CHECK: call {{.*}}__rust_alloc(i64 %[[BYTES]] // CHECK-NOT: call {{.*}}alloc::vec::from_elem // CHECK-NOT: call {{.*}}reserve