Rollup merge of #56548 - Lucretiel:string-extend-optimize, r=sfackler
Optimized string FromIterator + Extend impls I noticed that there was a lost opportunity to reuse string buffers in `FromIterator<String>` and `FromIterator<Cow<str>>`; updated the implementations to use these. In practice this translates to at least one fewer allocation when using these APIs. Additionally, rewrote `Extend` implementations to use `iter.for_each`, which (supposedly) helps the compiler optimize those loops (because iterator adapters are encouraged to provide optimized implementations of `fold` and `try_fold`.
This commit is contained in:
commit
e9e92d53ad
1 changed files with 29 additions and 18 deletions
|
|
@ -1732,18 +1732,37 @@ impl<'a> FromIterator<&'a str> for String {
|
|||
#[stable(feature = "extend_string", since = "1.4.0")]
|
||||
impl FromIterator<String> for String {
|
||||
fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String {
|
||||
let mut buf = String::new();
|
||||
buf.extend(iter);
|
||||
buf
|
||||
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) => {
|
||||
buf.extend(iterator);
|
||||
buf
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "herd_cows", since = "1.19.0")]
|
||||
impl<'a> FromIterator<Cow<'a, str>> for String {
|
||||
fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> String {
|
||||
let mut buf = String::new();
|
||||
buf.extend(iter);
|
||||
buf
|
||||
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) => {
|
||||
let mut buf = cow.into_owned();
|
||||
buf.extend(iterator);
|
||||
buf
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1753,9 +1772,7 @@ impl Extend<char> 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 +1786,21 @@ impl<'a> Extend<&'a char> for String {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> Extend<&'a str> for String {
|
||||
fn extend<I: IntoIterator<Item = &'a str>>(&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<String> for String {
|
||||
fn extend<I: IntoIterator<Item = String>>(&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<Cow<'a, str>> for String {
|
||||
fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
|
||||
for s in iter {
|
||||
self.push_str(&s)
|
||||
}
|
||||
iter.into_iter().for_each(move |s| self.push_str(&s));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue