Skip to content

Commit 4f862e6

Browse files
committed
Try to reuse buffers in String::extend
1 parent 57d8747 commit 4f862e6

File tree

1 file changed

+30
-14
lines changed

1 file changed

+30
-14
lines changed

library/alloc/src/string.rs

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,9 +1880,6 @@ impl FromIterator<String> for String {
18801880
fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String {
18811881
let mut iterator = iter.into_iter();
18821882

1883-
// Because we're iterating over `String`s, we can avoid at least
1884-
// one allocation by getting the first string from the iterator
1885-
// and appending to it all the subsequent strings.
18861883
match iterator.next() {
18871884
None => String::new(),
18881885
Some(mut buf) => {
@@ -1897,9 +1894,15 @@ impl FromIterator<String> for String {
18971894
#[stable(feature = "box_str2", since = "1.45.0")]
18981895
impl FromIterator<Box<str>> for String {
18991896
fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> String {
1900-
let mut buf = String::new();
1901-
buf.extend(iter);
1902-
buf
1897+
let mut iterator = iter.into_iter();
1898+
match iterator.next() {
1899+
None => String::new(),
1900+
Some(buf) => {
1901+
let mut buf = buf.into_string();
1902+
buf.extend(iter);
1903+
buf
1904+
}
1905+
}
19031906
}
19041907
}
19051908

@@ -1909,9 +1912,6 @@ impl<'a> FromIterator<Cow<'a, str>> for String {
19091912
fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> String {
19101913
let mut iterator = iter.into_iter();
19111914

1912-
// Because we're iterating over CoWs, we can (potentially) avoid at least
1913-
// one allocation by getting the first item and appending to it all the
1914-
// subsequent items.
19151915
match iterator.next() {
19161916
None => String::new(),
19171917
Some(cow) => {
@@ -1979,33 +1979,49 @@ impl<'a> Extend<&'a str> for String {
19791979
#[stable(feature = "box_str2", since = "1.45.0")]
19801980
impl Extend<Box<str>> for String {
19811981
fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
1982-
iter.into_iter().for_each(move |s| self.push_str(&s));
1982+
iter.into_iter().for_each(move |s| self.extend_one(s));
1983+
}
1984+
1985+
#[inline]
1986+
fn extend_one(&mut self, s: Box<str>) {
1987+
if self.is_empty() && s.len() >= self.capacity() {
1988+
*self = s.into_string();
1989+
} else {
1990+
self.push_str(&s);
1991+
}
19831992
}
19841993
}
19851994

19861995
#[cfg(not(no_global_oom_handling))]
19871996
#[stable(feature = "extend_string", since = "1.4.0")]
19881997
impl Extend<String> for String {
19891998
fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
1990-
iter.into_iter().for_each(move |s| self.push_str(&s));
1999+
iter.into_iter().for_each(move |s| self.extend_one(s))
19912000
}
19922001

19932002
#[inline]
19942003
fn extend_one(&mut self, s: String) {
1995-
self.push_str(&s);
2004+
if self.is_empty() && s.capacity() >= self.capacity() {
2005+
*self = s
2006+
} else {
2007+
self.push_str(&s)
2008+
}
19962009
}
19972010
}
19982011

19992012
#[cfg(not(no_global_oom_handling))]
20002013
#[stable(feature = "herd_cows", since = "1.19.0")]
20012014
impl<'a> Extend<Cow<'a, str>> for String {
20022015
fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
2003-
iter.into_iter().for_each(move |s| self.push_str(&s));
2016+
iter.into_iter().for_each(move |s| self.extend_one(s))
20042017
}
20052018

20062019
#[inline]
20072020
fn extend_one(&mut self, s: Cow<'a, str>) {
2008-
self.push_str(&s);
2021+
match s {
2022+
Cow::Owned(s) => self.extend_one(s),
2023+
Cow::Borrowed(s) => self.push_str(s),
2024+
}
20092025
}
20102026
}
20112027

0 commit comments

Comments
 (0)