From 180dcc3118998ebbe390f876df51f85f1b33407a Mon Sep 17 00:00:00 2001 From: Nathan West Date: Wed, 5 Dec 2018 14:37:38 -0800 Subject: [PATCH 1/3] Optimized string FromIterator impls --- src/liballoc/string.rs | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 662f8ae614fcb..ef9a34ec611c6 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1732,18 +1732,31 @@ impl<'a> FromIterator<&'a str> for String { #[stable(feature = "extend_string", since = "1.4.0")] impl FromIterator for String { fn from_iter>(iter: I) -> String { - let mut buf = String::new(); - buf.extend(iter); - buf + let iterator = iter.into_iter(); + + match iterator.next() { + None => String::new(), + Some(buf) => { + buf.extend(iterator); + buf + } + } } } #[stable(feature = "herd_cows", since = "1.19.0")] impl<'a> FromIterator> for String { fn from_iter>>(iter: I) -> String { - let mut buf = String::new(); - buf.extend(iter); - buf + let iterator = iter.into_iter(); + + match iterator.next() { + None => String::new(), + Some(cow) => { + let buf = cow.into_owned(); + buf.extend(iterator); + buf + } + } } } @@ -1753,9 +1766,7 @@ impl Extend for String { let iterator = iter.into_iter(); let (lower_bound, _) = iterator.size_hint(); self.reserve(lower_bound); - for ch in iterator { - self.push(ch) - } + iterator.for_each(move |c| self.push(c)); } } @@ -1769,27 +1780,21 @@ impl<'a> Extend<&'a char> for String { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Extend<&'a str> for String { fn extend>(&mut self, iter: I) { - for s in iter { - self.push_str(s) - } + iter.into_iter().for_each(move |s| self.push_str(s)); } } #[stable(feature = "extend_string", since = "1.4.0")] impl Extend for String { fn extend>(&mut self, iter: I) { - for s in iter { - self.push_str(&s) - } + iter.into_iter().for_each(move |s| self.push_str(&s)); } } #[stable(feature = "herd_cows", since = "1.19.0")] impl<'a> Extend> for String { fn extend>>(&mut self, iter: I) { - for s in iter { - self.push_str(&s) - } + iter.into_iter().for_each(move |s| self.push_str(&s)); } } From 823dd8ca334951962e8b192ca1362c08e33d6bcf Mon Sep 17 00:00:00 2001 From: Nathan West Date: Wed, 5 Dec 2018 15:11:32 -0800 Subject: [PATCH 2/3] Fixed mutability --- src/liballoc/string.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index ef9a34ec611c6..6962f2ba85296 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1732,11 +1732,11 @@ impl<'a> FromIterator<&'a str> for String { #[stable(feature = "extend_string", since = "1.4.0")] impl FromIterator for String { fn from_iter>(iter: I) -> String { - let iterator = iter.into_iter(); + let mut iterator = iter.into_iter(); match iterator.next() { None => String::new(), - Some(buf) => { + Some(mut buf) => { buf.extend(iterator); buf } @@ -1747,12 +1747,12 @@ impl FromIterator for String { #[stable(feature = "herd_cows", since = "1.19.0")] impl<'a> FromIterator> for String { fn from_iter>>(iter: I) -> String { - let iterator = iter.into_iter(); + let mut iterator = iter.into_iter(); match iterator.next() { None => String::new(), Some(cow) => { - let buf = cow.into_owned(); + let mut buf = cow.into_owned(); buf.extend(iterator); buf } From 811a2bfe5332081d7145de6c488ea7f6c5cf42a5 Mon Sep 17 00:00:00 2001 From: Nathan West Date: Wed, 5 Dec 2018 17:46:03 -0800 Subject: [PATCH 3/3] Added explainatory comments --- src/liballoc/string.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 6962f2ba85296..f0a64f4631a00 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1734,6 +1734,9 @@ impl FromIterator for String { fn from_iter>(iter: I) -> String { let mut iterator = iter.into_iter(); + // Because we're iterating over `String`s, we can avoid at least + // one allocation by getting the first string from the iterator + // and appending to it all the subsequent strings. match iterator.next() { None => String::new(), Some(mut buf) => { @@ -1749,6 +1752,9 @@ impl<'a> FromIterator> for String { fn from_iter>>(iter: I) -> String { let mut iterator = iter.into_iter(); + // Because we're iterating over CoWs, we can (potentially) avoid at least + // one allocation by getting the first item and appending to it all the + // subsequent items. match iterator.next() { None => String::new(), Some(cow) => {