about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCorey Farwell <coreyf@rwell.org>2017-03-28 23:19:23 -0400
committerGitHub <noreply@github.com>2017-03-28 23:19:23 -0400
commit8ae1d444cbd8515289818ee3e6c13bf30a7a227a (patch)
treef53171c166928f23c360bc837bf930ae2ea860b9
parent378d230dd4f9df9532024b7d9257a7bdecf6be15 (diff)
parentdae66e000a974dd3bea7ae10b8827a5ece2b941e (diff)
downloadrust-8ae1d444cbd8515289818ee3e6c13bf30a7a227a.tar.gz
rust-8ae1d444cbd8515289818ee3e6c13bf30a7a227a.zip
Rollup merge of #40731 - sfackler:vec-from-iter-spec, r=aturon
Specialize Vec::from_iter for vec::IntoIter

It's fairly common to expose an API which takes an `IntoIterator` and
immediately collects that into a vector. It's also common to buffer
a bunch of items into a vector and then pass that into one of these
APIs. If the iterator hasn't been advanced, we can make this `from_iter`
simply reassemble the original `Vec` with no actual iteration or
reallocation.

r? @aturon
-rw-r--r--src/libcollections/vec.rs29
-rw-r--r--src/libcollectionstest/vec.rs16
2 files changed, 41 insertions, 4 deletions
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index 7b408af13aa..56b60a3e003 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -1563,7 +1563,7 @@ impl<T> ops::DerefMut for Vec<T> {
 impl<T> FromIterator<T> for Vec<T> {
     #[inline]
     fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
-        <Self as SpecExtend<_, _>>::from_iter(iter.into_iter())
+        <Self as SpecExtend<T, I::IntoIter>>::from_iter(iter.into_iter())
     }
 }
 
@@ -1631,7 +1631,7 @@ impl<'a, T> IntoIterator for &'a mut Vec<T> {
 impl<T> Extend<T> for Vec<T> {
     #[inline]
     fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
-        self.spec_extend(iter.into_iter())
+        <Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter())
     }
 }
 
@@ -1662,7 +1662,7 @@ impl<T, I> SpecExtend<T, I> for Vec<T>
                 vector
             }
         };
-        vector.spec_extend(iterator);
+        <Vec<T> as SpecExtend<T, I>>::spec_extend(&mut vector, iterator);
         vector
     }
 
@@ -1674,7 +1674,7 @@ impl<T, I> SpecExtend<T, I> for Vec<T>
 impl<T, I> SpecExtend<T, I> for Vec<T>
     where I: TrustedLen<Item=T>,
 {
-    fn from_iter(iterator: I) -> Self {
+    default fn from_iter(iterator: I) -> Self {
         let mut vector = Vec::new();
         vector.spec_extend(iterator);
         vector
@@ -1706,6 +1706,27 @@ impl<T, I> SpecExtend<T, I> for Vec<T>
     }
 }
 
+impl<T> SpecExtend<T, IntoIter<T>> for Vec<T> {
+    fn from_iter(iterator: IntoIter<T>) -> Self {
+        // A common case is passing a vector into a function which immediately
+        // re-collects into a vector. We can short circuit this if the IntoIter
+        // has not been advanced at all.
+        if *iterator.buf == iterator.ptr as *mut T {
+            unsafe {
+                let vec = Vec::from_raw_parts(*iterator.buf as *mut T,
+                                              iterator.len(),
+                                              iterator.cap);
+                mem::forget(iterator);
+                vec
+            }
+        } else {
+            let mut vector = Vec::new();
+            vector.spec_extend(iterator);
+            vector
+        }
+    }
+}
+
 impl<'a, T: 'a, I> SpecExtend<&'a T, I> for Vec<T>
     where I: Iterator<Item=&'a T>,
           T: Clone,
diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs
index 06d70800d39..63df0eb7305 100644
--- a/src/libcollectionstest/vec.rs
+++ b/src/libcollectionstest/vec.rs
@@ -680,3 +680,19 @@ fn test_placement_panic() {
     let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); }));
     assert_eq!(vec.len(), 3);
 }
+
+#[test]
+fn from_into_inner() {
+    let vec = vec![1, 2, 3];
+    let ptr = vec.as_ptr();
+    let vec = vec.into_iter().collect::<Vec<_>>();
+    assert_eq!(vec, [1, 2, 3]);
+    assert_eq!(vec.as_ptr(), ptr);
+
+    let ptr = &vec[1] as *const _;
+    let mut it = vec.into_iter();
+    it.next().unwrap();
+    let vec = it.collect::<Vec<_>>();
+    assert_eq!(vec, [2, 3]);
+    assert!(ptr != vec.as_ptr());
+}