]> git.lizzy.rs Git - rust.git/commitdiff
Use specialization to avoid copying
authorDániel Buga <bugadani@gmail.com>
Fri, 30 Oct 2020 10:42:44 +0000 (11:42 +0100)
committerDániel Buga <bugadani@gmail.com>
Fri, 20 Nov 2020 20:02:09 +0000 (21:02 +0100)
compiler/rustc_arena/src/lib.rs

index b76e1e7ce65e00ade7e035f890ba3b9b9e5650aa..f468bad635a9baca66df23ecf507e3a409d783da 100644 (file)
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(no_crate_inject, attr(deny(warnings)))
 )]
+#![feature(array_value_iter_slice)]
 #![feature(dropck_eyepatch)]
 #![feature(new_uninit)]
 #![feature(maybe_uninit_slice)]
+#![feature(array_value_iter)]
+#![feature(min_const_generics)]
+#![feature(min_specialization)]
 #![cfg_attr(test, feature(test))]
 
 use smallvec::SmallVec;
@@ -114,6 +118,72 @@ fn default() -> TypedArena<T> {
     }
 }
 
+trait IterExt<T> {
+    fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T];
+}
+
+impl<I, T> IterExt<T> for I
+where
+    I: IntoIterator<Item = T>,
+{
+    #[inline]
+    default fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] {
+        let vec: SmallVec<[_; 8]> = self.into_iter().collect();
+        vec.alloc_from_iter(arena)
+    }
+}
+
+impl<T, const N: usize> IterExt<T> for std::array::IntoIter<T, N> {
+    #[inline]
+    fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] {
+        let len = self.len();
+        if len == 0 {
+            return &mut [];
+        }
+        // Move the content to the arena by copying and then forgetting it
+        unsafe {
+            let start_ptr = arena.alloc_raw_slice(len);
+            self.as_slice().as_ptr().copy_to_nonoverlapping(start_ptr, len);
+            mem::forget(self);
+            slice::from_raw_parts_mut(start_ptr, len)
+        }
+    }
+}
+
+impl<T> IterExt<T> for Vec<T> {
+    #[inline]
+    fn alloc_from_iter(mut self, arena: &TypedArena<T>) -> &mut [T] {
+        let len = self.len();
+        if len == 0 {
+            return &mut [];
+        }
+        // Move the content to the arena by copying and then forgetting it
+        unsafe {
+            let start_ptr = arena.alloc_raw_slice(len);
+            self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
+            self.set_len(0);
+            slice::from_raw_parts_mut(start_ptr, len)
+        }
+    }
+}
+
+impl<A: smallvec::Array> IterExt<A::Item> for SmallVec<A> {
+    #[inline]
+    fn alloc_from_iter(mut self, arena: &TypedArena<A::Item>) -> &mut [A::Item] {
+        let len = self.len();
+        if len == 0 {
+            return &mut [];
+        }
+        // Move the content to the arena by copying and then forgetting it
+        unsafe {
+            let start_ptr = arena.alloc_raw_slice(len);
+            self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
+            self.set_len(0);
+            slice::from_raw_parts_mut(start_ptr, len)
+        }
+    }
+}
+
 impl<T> TypedArena<T> {
     /// Allocates an object in the `TypedArena`, returning a reference to it.
     #[inline]
@@ -191,19 +261,7 @@ pub fn alloc_slice(&self, slice: &[T]) -> &mut [T]
     #[inline]
     pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] {
         assert!(mem::size_of::<T>() != 0);
-        let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect();
-        if vec.is_empty() {
-            return &mut [];
-        }
-        // Move the content to the arena by copying it and then forgetting
-        // the content of the SmallVec
-        unsafe {
-            let len = vec.len();
-            let start_ptr = self.alloc_raw_slice(len);
-            vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
-            vec.set_len(0);
-            slice::from_raw_parts_mut(start_ptr, len)
-        }
+        iter.alloc_from_iter(self)
     }
 
     /// Grows the arena.