diff options
| author | Corey Farwell <coreyf@rwell.org> | 2017-03-28 23:19:23 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-03-28 23:19:23 -0400 |
| commit | 8ae1d444cbd8515289818ee3e6c13bf30a7a227a (patch) | |
| tree | f53171c166928f23c360bc837bf930ae2ea860b9 | |
| parent | 378d230dd4f9df9532024b7d9257a7bdecf6be15 (diff) | |
| parent | dae66e000a974dd3bea7ae10b8827a5ece2b941e (diff) | |
| download | rust-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.rs | 29 | ||||
| -rw-r--r-- | src/libcollectionstest/vec.rs | 16 |
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()); +} |
