From 78344d176100b519b1d7de59cca8f6c26e8e2a70 Mon Sep 17 00:00:00 2001 From: Johan Walles Date: Fri, 4 Nov 2022 08:57:15 +0100 Subject: [PATCH] Implement our string builder --- m/reusableStringBuilder.go | 28 ++++++++++++++++++++++------ m/reusableStringBuilder_test.go | 19 +++++++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/m/reusableStringBuilder.go b/m/reusableStringBuilder.go index a69fe98..43d4767 100644 --- a/m/reusableStringBuilder.go +++ b/m/reusableStringBuilder.go @@ -1,16 +1,32 @@ package m +import "unicode/utf8" + type reusableStringBuilder struct { + buf []byte + length int // Number of used bytes in buf } -func (rsb reusableStringBuilder) Reset() { - panic("Unimplemented") +func (rsb *reusableStringBuilder) Reset() { + rsb.length = 0 } -func (rsb reusableStringBuilder) WriteRune(char rune) { - panic("Unimplemented") +// Inspired by the source code of strings.Builder +func (rsb *reusableStringBuilder) WriteRune(r rune) { + availableBytes := cap(rsb.buf) - rsb.length + if availableBytes < utf8.UTFMax { + newLength := 2*cap(rsb.buf) + utf8.UTFMax + newBuf := make([]byte, newLength) + for i := 0; i < rsb.length; i++ { + newBuf[i] = rsb.buf[i] + } + rsb.buf = newBuf + } + + encodedBytesCount := utf8.EncodeRune(rsb.buf[rsb.length:rsb.length+utf8.UTFMax], r) + rsb.length += encodedBytesCount } -func (rsb reusableStringBuilder) String() string { - panic("Unimplemented") +func (rsb *reusableStringBuilder) String() string { + return string(rsb.buf[0:rsb.length]) } diff --git a/m/reusableStringBuilder_test.go b/m/reusableStringBuilder_test.go index bb4f9ad..5c08d8f 100644 --- a/m/reusableStringBuilder_test.go +++ b/m/reusableStringBuilder_test.go @@ -15,6 +15,10 @@ func TestReusableStringBuilder_Basics(t *testing.T) { testMe.Reset() assert.Equal(t, "", testMe.String()) + + // Reset again to make sure it works when empty + testMe.Reset() + assert.Equal(t, "", testMe.String()) } // Ensure the strings returned by our builder are real, rather than just being @@ -32,3 +36,18 @@ func TestReusableStringBuilder_Copies(t *testing.T) { assert.Equal(t, s1, "a") assert.Equal(t, s2, "b") } + +func TestReusableStringBuilder_AddMultiple(t *testing.T) { + testMe := reusableStringBuilder{} + + // Should be more than utf8.UTFMax = 4 to force one expansion when we + // already have data + testMe.WriteRune('a') + testMe.WriteRune('b') + testMe.WriteRune('c') + testMe.WriteRune('d') + testMe.WriteRune('e') + testMe.WriteRune('f') + + assert.Equal(t, testMe.String(), "abcdef") +}