1616struct StringBuilder {
1717 mut data : FixedArray [UInt16 ]
1818 mut len : Int
19+ mut buffer_is_shared : Bool
1920}
2021
2122///|
@@ -33,7 +34,7 @@ struct StringBuilder {
3334pub fn StringBuilder ::StringBuilder (size_hint? : Int = 0) -> StringBuilder {
3435 let initial = if size_hint < 1 { 1 } else { (size_hint + 1) / 2 }
3536 let data : FixedArray [UInt16 ] = FixedArray ::make(initial, 0)
36- { data, len: 0 }
37+ { data, len: 0, buffer_is_shared: false }
3738}
3839
3940///|
@@ -84,6 +85,7 @@ fn StringBuilder::grow(self : StringBuilder, required : Int) -> Unit {
8485 len=self.len,
8586 )
8687 self.data = new_data
88+ self.buffer_is_shared = false
8789}
8890
8991///|
@@ -184,6 +186,9 @@ pub fn StringBuilder::to_string(self : StringBuilder) -> String {
184186 if self.len == 0 {
185187 ""
186188 } else if self.len == self.data.length() {
189+ // This conversion can reuse `data` without copying, so future resets must
190+ // detach before the buffer is written again.
191+ self.buffer_is_shared = true
187192 unsafe_fixedarray_uint16_to_string(self.data)
188193 } else {
189194 let data = FixedArray ::make_and_blit(
@@ -210,9 +215,14 @@ pub impl Show for StringBuilder with fn to_string(self) {
210215///|
211216/// Resets the string builder to an empty state.
212217pub fn StringBuilder ::reset(self : StringBuilder ) -> Unit {
213- self.data = FixedArray ::make(
214- self.data.length(),
215- (Default ::default() : UInt16 ),
216- )
218+ // A full buffer may have been returned directly from `to_string`. Retain the
219+ // backing storage in every other case, since it only contains value types.
220+ if self.buffer_is_shared {
221+ self.data = FixedArray ::make(
222+ self.data.length(),
223+ (Default ::default() : UInt16 ),
224+ )
225+ self.buffer_is_shared = false
226+ }
217227 self.len = 0
218228}
0 commit comments