From 76a3b5596108fffbb0902d3d3ef27142a909be37 Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Fri, 8 Nov 2019 15:24:24 +0530 Subject: [PATCH 01/15] Added AddAssign implementation for String --- src/liballoc/borrow.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index d2bdda83fa998..6999d4b80ee58 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -479,3 +479,18 @@ impl<'a> AddAssign> for Cow<'a, str> { } } } + +impl<'a> AddAssign for Cow<'a, str> { + fn add_assign(&mut self, rhs: char) { + if self.is_empty() { + *self = rhs.to_string() + } else { + if let Cow::Borrowed(lhs) = *self { + let mut s = String::with_capacity(lhs.len() + rhs.len_utf8()); + s.push_str(lhs); + *self = Cow::Owned(s); + } + self.to_mut().push(rhs); + } + } +} \ No newline at end of file From ed523729f5d865ff73efa1254e3a2fe15e43a0be Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Fri, 8 Nov 2019 23:47:51 +0530 Subject: [PATCH 02/15] Amended with the suggested syntax+improvements --- src/liballoc/borrow.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index 6999d4b80ee58..536cfd840aa3c 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -480,17 +480,14 @@ impl<'a> AddAssign> for Cow<'a, str> { } } -impl<'a> AddAssign for Cow<'a, str> { +#[stable(feature = "cow_str_add_assign_char", since = "1.41.0")] +impl AddAssign for Cow<'_, str> { fn add_assign(&mut self, rhs: char) { - if self.is_empty() { - *self = rhs.to_string() - } else { - if let Cow::Borrowed(lhs) = *self { - let mut s = String::with_capacity(lhs.len() + rhs.len_utf8()); - s.push_str(lhs); - *self = Cow::Owned(s); - } - self.to_mut().push(rhs); + if let Cow::Borrowed(lhs) = *self { + let mut s = String::with_capacity(lhs.len() + rhs.len_utf8()); + s.push_str(lhs); + *self = Cow::Owned(s); } + self.to_mut().push(rhs); } } \ No newline at end of file From 342277f3a385f23f43f6ddb203d232815f72f46b Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Sat, 9 Nov 2019 03:08:24 +0530 Subject: [PATCH 03/15] Ammended further to accomodate `AddAssign` for `String` and `Cow`. Added `impl Add for String` to ascertain logical parity. --- src/liballoc/borrow.rs | 2 +- src/liballoc/string.rs | 56 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index 536cfd840aa3c..f2dfa9063b797 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -490,4 +490,4 @@ impl AddAssign for Cow<'_, str> { } self.to_mut().push(rhs); } -} \ No newline at end of file +} diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index f7dff4c21f7c4..ccc887d789ccf 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1982,6 +1982,51 @@ impl Add<&str> for String { } } +/// Implements the `+` operator for concatenating a string and a char together. +/// +/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if +/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on +/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by +/// repeated concatenation. +/// +/// # Examples +/// +/// Concatenating a `String` with a `char` takes the `String` by value and copies the `char`: +/// +/// ``` +/// let a = String::from("hello world! "); +/// let b = char::from('👋'); +/// let c = a + b; +/// // `a` is moved and can no longer be used here. +/// ``` +/// +/// If you want to keep using the initial `String`, you can clone it and append to the clone instead: +/// +/// ``` +/// let a = String::from("hello world! "); +/// let b = char::from('👋'); +/// let c = a.clone() + b; +/// // `a` is still valid here. +/// ``` +/// +/// Concatenating `char` to a `&str` slice can be done by converting the `&str` to a `String`: +/// +/// ``` +/// let a = "hello world! "; +/// let b = '👋'; +/// let c = a.to_string() + b; +/// ``` +#[stable(feature = "add_string_and_char", since = "1.41.0")] +impl Add for String { + type Output = String; + + #[inline] + fn add(mut self, other: char) -> String { + self.push(other); + self + } +} + /// Implements the `+=` operator for appending to a `String`. /// /// This has the same behavior as the [`push_str`][String::push_str] method. @@ -1993,6 +2038,17 @@ impl AddAssign<&str> for String { } } +/// Implements the `+=` operator for appending a `char` to a `String`. +/// +/// This has the same behavior as the [`push`][String::push] method. +#[stable(feature = "stringaddassign_char", since = "1.41.0")] +impl AddAssign for String { + #[inline] + fn add_assign(&mut self, other: char) { + self.push(other); + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for String { type Output = str; From 9b55f6bd72016999efe0711a95bda3ab590bbf72 Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Sat, 9 Nov 2019 09:46:59 +0530 Subject: [PATCH 04/15] Added tests for the respective AddAssign/Add operations for `char` concatenation to `String` and `Cow`. --- src/liballoc/tests/cow_str.rs | 30 ++++++++++++++++++++++++++++++ src/liballoc/tests/string.rs | 13 ++++++++----- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/liballoc/tests/cow_str.rs b/src/liballoc/tests/cow_str.rs index 6f357eda9b83b..4e1c8a1846e09 100644 --- a/src/liballoc/tests/cow_str.rs +++ b/src/liballoc/tests/cow_str.rs @@ -139,3 +139,33 @@ fn check_cow_clone_from() { c1.clone_from(&c2); assert!(c1.into_owned().capacity() >= 25); } + +#[test] +fn check_cow_add_assign_char() { + let test_char = '👋'; + + let mut borrowed = Cow::Borrowed("Hello, World! "); + let borrow_empty = Cow::Borrowed(""); + + let mut owned: Cow<'_, str> = Cow::Owned(String::from("Hi, World! ")); + let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); + + let mut s = borrow_empty.clone(); + s += test_char; + assert_eq!(test_char.to_string(), s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + let mut s = owned_empty.clone(); + s += test_char; + assert_eq!(test_char.to_string(), s); + if let Cow::Owned(_) = s { + panic!("Adding empty strings to a borrow should note allocate"); + } + + owned += test_char; + borrowed += test_char; + + assert_eq!(format!("Hi, World! {}", test_char), owned); + assert_eq!(format!("Hello, World! {}", test_char), borrowed); +} diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 55edf56345b59..81f66d9e67f49 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -195,8 +195,10 @@ fn test_add_assign() { assert_eq!(s.as_str(), ""); s += "abc"; assert_eq!(s.as_str(), "abc"); - s += "ประเทศไทย中华Việt Nam"; - assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam"); + s += "ประเทศไทย中华Việt Nam "; + assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam "); + s += '👋'; + assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam 👋") } #[test] @@ -304,9 +306,10 @@ fn test_str_clear() { fn test_str_add() { let a = String::from("12345"); let b = a + "2"; - let b = b + "2"; - assert_eq!(b.len(), 7); - assert_eq!(b, "1234522"); + let b = b + "2 "; + let b = b + '👋'; + assert_eq!(b.len(), 12); + assert_eq!(b, "1234522 👋"); } #[test] From cd2ad6dd0bb918fab878afe21b5fa42abff60595 Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Tue, 12 Nov 2019 03:06:38 +0530 Subject: [PATCH 05/15] Re-implemented so that Cow::Borrowed now gets allocated using the inherent amortized logic for RawVec. --- src/liballoc/borrow.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index f2dfa9063b797..1602301c055aa 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -484,7 +484,9 @@ impl<'a> AddAssign> for Cow<'a, str> { impl AddAssign for Cow<'_, str> { fn add_assign(&mut self, rhs: char) { if let Cow::Borrowed(lhs) = *self { - let mut s = String::with_capacity(lhs.len() + rhs.len_utf8()); + let mut s = String::with_capacity(s.len() + rhs.len_utf8()); + // 4 bytes more since we know `rhs.len_utf8() <= 4` + s.vec.buf.amortized_new_size(s.capacity(), 4).expect("capacity overflow"); s.push_str(lhs); *self = Cow::Owned(s); } From 12a32e6297655bc582079a0375194629c6bdd21d Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Tue, 12 Nov 2019 03:11:15 +0530 Subject: [PATCH 06/15] Replaced wrongly used s.len() with lhs.len() --- src/liballoc/borrow.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index 1602301c055aa..2477663216d99 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -484,7 +484,7 @@ impl<'a> AddAssign> for Cow<'a, str> { impl AddAssign for Cow<'_, str> { fn add_assign(&mut self, rhs: char) { if let Cow::Borrowed(lhs) = *self { - let mut s = String::with_capacity(s.len() + rhs.len_utf8()); + let mut s = String::with_capacity(lhs.len() + rhs.len_utf8()); // 4 bytes more since we know `rhs.len_utf8() <= 4` s.vec.buf.amortized_new_size(s.capacity(), 4).expect("capacity overflow"); s.push_str(lhs); From 543a0b6634186d16d5423019566fa98923462945 Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Tue, 12 Nov 2019 03:27:52 +0530 Subject: [PATCH 07/15] Added String::reserve_exact() to reserve the optimal space. --- src/liballoc/borrow.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index 2477663216d99..9f13e8fa899a9 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -486,7 +486,8 @@ impl AddAssign for Cow<'_, str> { if let Cow::Borrowed(lhs) = *self { let mut s = String::with_capacity(lhs.len() + rhs.len_utf8()); // 4 bytes more since we know `rhs.len_utf8() <= 4` - s.vec.buf.amortized_new_size(s.capacity(), 4).expect("capacity overflow"); + let new_optimal_size = s.vec.buf.amortized_new_size(s.capacity(), 4).expect("capacity overflow"); + s.reserve_exact(new_optimal_size - s.capacity()); s.push_str(lhs); *self = Cow::Owned(s); } From ea5f056be3d03c1621c13932559c256867b6dab1 Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Tue, 12 Nov 2019 03:53:45 +0530 Subject: [PATCH 08/15] Changed code logic to call RawVec::amortized_new_size() from preallocated lhs --- src/liballoc/borrow.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index 9f13e8fa899a9..e5f8d611b2a7f 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -484,10 +484,10 @@ impl<'a> AddAssign> for Cow<'a, str> { impl AddAssign for Cow<'_, str> { fn add_assign(&mut self, rhs: char) { if let Cow::Borrowed(lhs) = *self { - let mut s = String::with_capacity(lhs.len() + rhs.len_utf8()); + let base_capacity = lhs.len() + rhs.len_utf8(); // 4 bytes more since we know `rhs.len_utf8() <= 4` - let new_optimal_size = s.vec.buf.amortized_new_size(s.capacity(), 4).expect("capacity overflow"); - s.reserve_exact(new_optimal_size - s.capacity()); + let new_optimal_size = lhs.vec.buf.amortized_new_size(base_capacity, 4).expect("capacity overflow"); + let mut s = String::with_capacity(new_optimal_size); s.push_str(lhs); *self = Cow::Owned(s); } From 7d875042fbb88484c48f4010572dd0110e82bc64 Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Sat, 16 Nov 2019 09:40:47 +0530 Subject: [PATCH 09/15] Allocate new string using inline amortized logic. --- src/liballoc/borrow.rs | 4 ++-- src/liballoc/string.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index e5f8d611b2a7f..2d36d6b1891b6 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -485,8 +485,8 @@ impl AddAssign for Cow<'_, str> { fn add_assign(&mut self, rhs: char) { if let Cow::Borrowed(lhs) = *self { let base_capacity = lhs.len() + rhs.len_utf8(); - // 4 bytes more since we know `rhs.len_utf8() <= 4` - let new_optimal_size = lhs.vec.buf.amortized_new_size(base_capacity, 4).expect("capacity overflow"); + //Attempt amortized memory allocation + let new_optimal_size = cmp::max(base_capacity * 2, base_capacity); let mut s = String::with_capacity(new_optimal_size); s.push_str(lhs); *self = Cow::Owned(s); diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index ccc887d789ccf..a6ce47acb9364 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1995,7 +1995,7 @@ impl Add<&str> for String { /// /// ``` /// let a = String::from("hello world! "); -/// let b = char::from('👋'); +/// let b = '👋'; /// let c = a + b; /// // `a` is moved and can no longer be used here. /// ``` @@ -2004,7 +2004,7 @@ impl Add<&str> for String { /// /// ``` /// let a = String::from("hello world! "); -/// let b = char::from('👋'); +/// let b = '👋'; /// let c = a.clone() + b; /// // `a` is still valid here. /// ``` From d62e867a84458c31975751ce396d389a0db2cb99 Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Wed, 20 Nov 2019 06:23:42 +0530 Subject: [PATCH 10/15] Revert "Added tests for the respective AddAssign/Add operations for `char` concatenation to `String` and `Cow`." This reverts commit 9b55f6bd72016999efe0711a95bda3ab590bbf72. --- src/liballoc/tests/cow_str.rs | 30 ------------------------------ src/liballoc/tests/string.rs | 13 +++++-------- 2 files changed, 5 insertions(+), 38 deletions(-) diff --git a/src/liballoc/tests/cow_str.rs b/src/liballoc/tests/cow_str.rs index 4e1c8a1846e09..6f357eda9b83b 100644 --- a/src/liballoc/tests/cow_str.rs +++ b/src/liballoc/tests/cow_str.rs @@ -139,33 +139,3 @@ fn check_cow_clone_from() { c1.clone_from(&c2); assert!(c1.into_owned().capacity() >= 25); } - -#[test] -fn check_cow_add_assign_char() { - let test_char = '👋'; - - let mut borrowed = Cow::Borrowed("Hello, World! "); - let borrow_empty = Cow::Borrowed(""); - - let mut owned: Cow<'_, str> = Cow::Owned(String::from("Hi, World! ")); - let owned_empty: Cow<'_, str> = Cow::Owned(String::new()); - - let mut s = borrow_empty.clone(); - s += test_char; - assert_eq!(test_char.to_string(), s); - if let Cow::Owned(_) = s { - panic!("Adding empty strings to a borrow should note allocate"); - } - let mut s = owned_empty.clone(); - s += test_char; - assert_eq!(test_char.to_string(), s); - if let Cow::Owned(_) = s { - panic!("Adding empty strings to a borrow should note allocate"); - } - - owned += test_char; - borrowed += test_char; - - assert_eq!(format!("Hi, World! {}", test_char), owned); - assert_eq!(format!("Hello, World! {}", test_char), borrowed); -} diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 81f66d9e67f49..55edf56345b59 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -195,10 +195,8 @@ fn test_add_assign() { assert_eq!(s.as_str(), ""); s += "abc"; assert_eq!(s.as_str(), "abc"); - s += "ประเทศไทย中华Việt Nam "; - assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam "); - s += '👋'; - assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam 👋") + s += "ประเทศไทย中华Việt Nam"; + assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam"); } #[test] @@ -306,10 +304,9 @@ fn test_str_clear() { fn test_str_add() { let a = String::from("12345"); let b = a + "2"; - let b = b + "2 "; - let b = b + '👋'; - assert_eq!(b.len(), 12); - assert_eq!(b, "1234522 👋"); + let b = b + "2"; + assert_eq!(b.len(), 7); + assert_eq!(b, "1234522"); } #[test] From f2ac3958e6f97d86dd10fabb608e164e64f64eee Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Wed, 20 Nov 2019 06:36:22 +0530 Subject: [PATCH 11/15] Revert "Ammended further to accomodate `AddAssign` for `String` and `Cow`." This reverts commit 342277f3a385f23f43f6ddb203d232815f72f46b. --- src/doc/nomicon | 2 +- src/liballoc/borrow.rs | 2 +- src/liballoc/string.rs | 14 +++----------- src/llvm-project | 2 +- src/tools/cargo | 2 +- 5 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/doc/nomicon b/src/doc/nomicon index 5004ad30d69f9..58e36e0e08dec 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 5004ad30d69f93553ceef74439fea2159d1f769e +Subproject commit 58e36e0e08dec5a379ac568827c058e25990d6cd diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index 2d36d6b1891b6..400a9dede8c10 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -493,4 +493,4 @@ impl AddAssign for Cow<'_, str> { } self.to_mut().push(rhs); } -} +} \ No newline at end of file diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index a6ce47acb9364..e6a452fa00699 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1982,6 +1982,7 @@ impl Add<&str> for String { } } +<<<<<<< HEAD /// Implements the `+` operator for concatenating a string and a char together. /// /// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if @@ -2027,6 +2028,8 @@ impl Add for String { } } +======= +>>>>>>> parent of 342277f3a38... Ammended further to accomodate `AddAssign` for `String` and `Cow`. /// Implements the `+=` operator for appending to a `String`. /// /// This has the same behavior as the [`push_str`][String::push_str] method. @@ -2038,17 +2041,6 @@ impl AddAssign<&str> for String { } } -/// Implements the `+=` operator for appending a `char` to a `String`. -/// -/// This has the same behavior as the [`push`][String::push] method. -#[stable(feature = "stringaddassign_char", since = "1.41.0")] -impl AddAssign for String { - #[inline] - fn add_assign(&mut self, other: char) { - self.push(other); - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl ops::Index> for String { type Output = str; diff --git a/src/llvm-project b/src/llvm-project index 14a3b123074e0..cf9304d6d0c6a 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 14a3b123074e066d64a99886941473058e52197d +Subproject commit cf9304d6d0c6a66c27a1664dd55d8bcc8be0bf09 diff --git a/src/tools/cargo b/src/tools/cargo index 5da4b4d479638..8280633db680d 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 5da4b4d47963868d9878480197581ccbbdaece74 +Subproject commit 8280633db680dec5bfe1de25156d1a1d53e6d190 From 0704d9b7e36f82c310cec6c1dfc5ab16a1068249 Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Wed, 20 Nov 2019 06:37:38 +0530 Subject: [PATCH 12/15] Revert "Ammended further to accomodate `AddAssign` for `String` and `Cow`." This reverts commit 342277f3a385f23f43f6ddb203d232815f72f46b. --- src/liballoc/string.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index e6a452fa00699..a5ffe54eb29e8 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1982,6 +1982,7 @@ impl Add<&str> for String { } } +<<<<<<< HEAD <<<<<<< HEAD /// Implements the `+` operator for concatenating a string and a char together. /// @@ -2028,6 +2029,8 @@ impl Add for String { } } +======= +>>>>>>> parent of 342277f3a38... Ammended further to accomodate `AddAssign` for `String` and `Cow`. ======= >>>>>>> parent of 342277f3a38... Ammended further to accomodate `AddAssign` for `String` and `Cow`. /// Implements the `+=` operator for appending to a `String`. From 56230442ac2e11e766dc160d50376010369b6ba4 Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Wed, 20 Nov 2019 07:04:26 +0530 Subject: [PATCH 13/15] Revert to the start of PR --- src/doc/nomicon | 2 +- src/liballoc/borrow.rs | 20 ++++++++--------- src/liballoc/string.rs | 51 ------------------------------------------ src/llvm-project | 2 +- src/tools/cargo | 2 +- 5 files changed, 13 insertions(+), 64 deletions(-) diff --git a/src/doc/nomicon b/src/doc/nomicon index 58e36e0e08dec..5004ad30d69f9 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 58e36e0e08dec5a379ac568827c058e25990d6cd +Subproject commit 5004ad30d69f93553ceef74439fea2159d1f769e diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index 400a9dede8c10..6999d4b80ee58 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -480,17 +480,17 @@ impl<'a> AddAssign> for Cow<'a, str> { } } -#[stable(feature = "cow_str_add_assign_char", since = "1.41.0")] -impl AddAssign for Cow<'_, str> { +impl<'a> AddAssign for Cow<'a, str> { fn add_assign(&mut self, rhs: char) { - if let Cow::Borrowed(lhs) = *self { - let base_capacity = lhs.len() + rhs.len_utf8(); - //Attempt amortized memory allocation - let new_optimal_size = cmp::max(base_capacity * 2, base_capacity); - let mut s = String::with_capacity(new_optimal_size); - s.push_str(lhs); - *self = Cow::Owned(s); + if self.is_empty() { + *self = rhs.to_string() + } else { + if let Cow::Borrowed(lhs) = *self { + let mut s = String::with_capacity(lhs.len() + rhs.len_utf8()); + s.push_str(lhs); + *self = Cow::Owned(s); + } + self.to_mut().push(rhs); } - self.to_mut().push(rhs); } } \ No newline at end of file diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index a5ffe54eb29e8..f7dff4c21f7c4 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1982,57 +1982,6 @@ impl Add<&str> for String { } } -<<<<<<< HEAD -<<<<<<< HEAD -/// Implements the `+` operator for concatenating a string and a char together. -/// -/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if -/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on -/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by -/// repeated concatenation. -/// -/// # Examples -/// -/// Concatenating a `String` with a `char` takes the `String` by value and copies the `char`: -/// -/// ``` -/// let a = String::from("hello world! "); -/// let b = '👋'; -/// let c = a + b; -/// // `a` is moved and can no longer be used here. -/// ``` -/// -/// If you want to keep using the initial `String`, you can clone it and append to the clone instead: -/// -/// ``` -/// let a = String::from("hello world! "); -/// let b = '👋'; -/// let c = a.clone() + b; -/// // `a` is still valid here. -/// ``` -/// -/// Concatenating `char` to a `&str` slice can be done by converting the `&str` to a `String`: -/// -/// ``` -/// let a = "hello world! "; -/// let b = '👋'; -/// let c = a.to_string() + b; -/// ``` -#[stable(feature = "add_string_and_char", since = "1.41.0")] -impl Add for String { - type Output = String; - - #[inline] - fn add(mut self, other: char) -> String { - self.push(other); - self - } -} - -======= ->>>>>>> parent of 342277f3a38... Ammended further to accomodate `AddAssign` for `String` and `Cow`. -======= ->>>>>>> parent of 342277f3a38... Ammended further to accomodate `AddAssign` for `String` and `Cow`. /// Implements the `+=` operator for appending to a `String`. /// /// This has the same behavior as the [`push_str`][String::push_str] method. diff --git a/src/llvm-project b/src/llvm-project index cf9304d6d0c6a..14a3b123074e0 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit cf9304d6d0c6a66c27a1664dd55d8bcc8be0bf09 +Subproject commit 14a3b123074e066d64a99886941473058e52197d diff --git a/src/tools/cargo b/src/tools/cargo index 8280633db680d..5da4b4d479638 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 8280633db680dec5bfe1de25156d1a1d53e6d190 +Subproject commit 5da4b4d47963868d9878480197581ccbbdaece74 From 5d2184b8e8915d98fb36896edba13d73a82cb991 Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Wed, 20 Nov 2019 07:53:50 +0530 Subject: [PATCH 14/15] impl Add and AddAssign for Cow<'_, str> --- src/liballoc/borrow.rs | 35 +++++++++++++++++++++++------------ src/liballoc/tests/cow_str.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index 6999d4b80ee58..f01568c90caac 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -2,7 +2,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -use core::cmp::Ordering; +use core::cmp::{Ordering, max}; use core::hash::{Hash, Hasher}; use core::ops::{Add, AddAssign, Deref}; @@ -444,6 +444,17 @@ impl<'a> Add> for Cow<'a, str> { } } +#[stable(feature = "cow_str_add_char", since = "1.41.0")] +impl<'a> Add for Cow<'a, str> { + type Output = Cow<'a, str>; + + #[inline] + fn add(mut self, rhs: char) -> Self::Output { + self += rhs; + self + } +} + #[stable(feature = "cow_add", since = "1.14.0")] impl<'a> AddAssign<&'a str> for Cow<'a, str> { fn add_assign(&mut self, rhs: &'a str) { @@ -480,17 +491,17 @@ impl<'a> AddAssign> for Cow<'a, str> { } } -impl<'a> AddAssign for Cow<'a, str> { +#[stable(feature = "cow_str_add_assign_char", since = "1.41.0")] +impl AddAssign for Cow<'_, str> { fn add_assign(&mut self, rhs: char) { - if self.is_empty() { - *self = rhs.to_string() - } else { - if let Cow::Borrowed(lhs) = *self { - let mut s = String::with_capacity(lhs.len() + rhs.len_utf8()); - s.push_str(lhs); - *self = Cow::Owned(s); - } - self.to_mut().push(rhs); + if let Cow::Borrowed(lhs) = *self { + let base_capacity = lhs.len() + rhs.len_utf8(); + //Attempt amortized memory allocation + let new_optimal_size = max(base_capacity * 2, base_capacity); + let mut s = String::with_capacity(new_optimal_size); + s.push_str(lhs); + *self = Cow::Owned(s); } + self.to_mut().push(rhs); } -} \ No newline at end of file +} diff --git a/src/liballoc/tests/cow_str.rs b/src/liballoc/tests/cow_str.rs index 6f357eda9b83b..16083ec24acf1 100644 --- a/src/liballoc/tests/cow_str.rs +++ b/src/liballoc/tests/cow_str.rs @@ -54,6 +54,20 @@ fn check_cow_add_str() { } } +#[test] +fn check_cow_add_char() { + let test_char = '👋'; + + let borrowed = Cow::Borrowed("Hello, World! "); + + let owned: Cow<'_, str> = Cow::Owned(String::from("Hi, World! ")); + + assert_eq!("Hello, World! 👋", borrowed.clone() + '👋'); + + assert_eq!("Hi, World! 👋", owned.clone() + '👋'); +} + + #[test] fn check_cow_add_assign_cow() { let mut borrowed1 = Cow::Borrowed("Hello, "); @@ -139,3 +153,18 @@ fn check_cow_clone_from() { c1.clone_from(&c2); assert!(c1.into_owned().capacity() >= 25); } + +#[test] +fn check_cow_add_assign_char() { + let test_char = '👋'; + + let mut borrowed = Cow::Borrowed("Hello, World! "); + + let mut owned: Cow<'_, str> = Cow::Owned(String::from("Hi, World! ")); + + owned += test_char; + borrowed += test_char; + + assert_eq!(format!("Hi, World! {}", test_char), owned); + assert_eq!(format!("Hello, World! {}", test_char), borrowed); +} From 47d0179a13162d96084217f89b83ec1dd6603270 Mon Sep 17 00:00:00 2001 From: Ruster-a11y Date: Wed, 20 Nov 2019 09:22:51 +0530 Subject: [PATCH 15/15] Fixed unused variable error in tests\cow_str.rs --- src/liballoc/tests/cow_str.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/liballoc/tests/cow_str.rs b/src/liballoc/tests/cow_str.rs index 16083ec24acf1..c28a8607af71f 100644 --- a/src/liballoc/tests/cow_str.rs +++ b/src/liballoc/tests/cow_str.rs @@ -62,9 +62,9 @@ fn check_cow_add_char() { let owned: Cow<'_, str> = Cow::Owned(String::from("Hi, World! ")); - assert_eq!("Hello, World! 👋", borrowed.clone() + '👋'); + assert_eq!("Hello, World! 👋", borrowed.clone() + test_char); - assert_eq!("Hi, World! 👋", owned.clone() + '👋'); + assert_eq!("Hi, World! 👋", owned.clone() + test_char); }