Skip to content

Commit 432d116

Browse files
committed
Auto merge of #78569 - bugadani:arena-spec, r=Mark-Simulacrum
Arena: use specialization to avoid copying data In several cases, a `Vec` or `SmallVec` is passed to `Arena::alloc_from_iter` directly. This PR makes sure those cases don't copy their data unnecessarily, by specializing the `alloc_from_iter` implementation.
2 parents 593fe97 + e93a463 commit 432d116

File tree

1 file changed

+71
-13
lines changed
  • compiler/rustc_arena/src

1 file changed

+71
-13
lines changed

Diff for: compiler/rustc_arena/src/lib.rs

+71-13
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
1212
test(no_crate_inject, attr(deny(warnings)))
1313
)]
14+
#![feature(array_value_iter_slice)]
1415
#![feature(dropck_eyepatch)]
1516
#![feature(new_uninit)]
1617
#![feature(maybe_uninit_slice)]
18+
#![feature(array_value_iter)]
19+
#![feature(min_const_generics)]
20+
#![feature(min_specialization)]
1721
#![cfg_attr(test, feature(test))]
1822

1923
use smallvec::SmallVec;
@@ -114,6 +118,72 @@ impl<T> Default for TypedArena<T> {
114118
}
115119
}
116120

121+
trait IterExt<T> {
122+
fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T];
123+
}
124+
125+
impl<I, T> IterExt<T> for I
126+
where
127+
I: IntoIterator<Item = T>,
128+
{
129+
#[inline]
130+
default fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] {
131+
let vec: SmallVec<[_; 8]> = self.into_iter().collect();
132+
vec.alloc_from_iter(arena)
133+
}
134+
}
135+
136+
impl<T, const N: usize> IterExt<T> for std::array::IntoIter<T, N> {
137+
#[inline]
138+
fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] {
139+
let len = self.len();
140+
if len == 0 {
141+
return &mut [];
142+
}
143+
// Move the content to the arena by copying and then forgetting it
144+
unsafe {
145+
let start_ptr = arena.alloc_raw_slice(len);
146+
self.as_slice().as_ptr().copy_to_nonoverlapping(start_ptr, len);
147+
mem::forget(self);
148+
slice::from_raw_parts_mut(start_ptr, len)
149+
}
150+
}
151+
}
152+
153+
impl<T> IterExt<T> for Vec<T> {
154+
#[inline]
155+
fn alloc_from_iter(mut self, arena: &TypedArena<T>) -> &mut [T] {
156+
let len = self.len();
157+
if len == 0 {
158+
return &mut [];
159+
}
160+
// Move the content to the arena by copying and then forgetting it
161+
unsafe {
162+
let start_ptr = arena.alloc_raw_slice(len);
163+
self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
164+
self.set_len(0);
165+
slice::from_raw_parts_mut(start_ptr, len)
166+
}
167+
}
168+
}
169+
170+
impl<A: smallvec::Array> IterExt<A::Item> for SmallVec<A> {
171+
#[inline]
172+
fn alloc_from_iter(mut self, arena: &TypedArena<A::Item>) -> &mut [A::Item] {
173+
let len = self.len();
174+
if len == 0 {
175+
return &mut [];
176+
}
177+
// Move the content to the arena by copying and then forgetting it
178+
unsafe {
179+
let start_ptr = arena.alloc_raw_slice(len);
180+
self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
181+
self.set_len(0);
182+
slice::from_raw_parts_mut(start_ptr, len)
183+
}
184+
}
185+
}
186+
117187
impl<T> TypedArena<T> {
118188
/// Allocates an object in the `TypedArena`, returning a reference to it.
119189
#[inline]
@@ -191,19 +261,7 @@ impl<T> TypedArena<T> {
191261
#[inline]
192262
pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
193263
assert!(mem::size_of::<T>() != 0);
194-
let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
195-
if vec.is_empty() {
196-
return &mut [];
197-
}
198-
// Move the content to the arena by copying it and then forgetting
199-
// the content of the SmallVec
200-
unsafe {
201-
let len = vec.len();
202-
let start_ptr = self.alloc_raw_slice(len);
203-
vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
204-
vec.set_len(0);
205-
slice::from_raw_parts_mut(start_ptr, len)
206-
}
264+
iter.alloc_from_iter(self)
207265
}
208266

209267
/// Grows the arena.

0 commit comments

Comments
 (0)