From 82f902ae8e2b7f7eff0cdb087e47e939cc296a62 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Martin=20M=C3=B6hrmann?= Date: Mon, 1 Nov 2021 06:42:01 +0100 Subject: [PATCH] strings: align Clone output with string([]byte("")) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Add a comment how strings of length 0 are treated and that they always will result in the return of a string equal to the constant string "". The previous implementation would return a string header that uses runtime.zerobase as the backing array pointer while the string constant "" has 0 as pointer value. Using 0 has the backing array pointer is also the behaviour of string([]byte(input)) which makes the new behaviour a better drop in replacement. Change-Id: Ic5460e9494b6708edbdfa4361e878d50db54ba10 Reviewed-on: https://go-review.googlesource.com/c/go/+/360255 Trust: Martin Möhrmann Run-TryBot: Martin Möhrmann TryBot-Result: Go Bot Reviewed-by: Russ Cox --- src/strings/clone.go | 5 +++++ src/strings/clone_test.go | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/strings/clone.go b/src/strings/clone.go index 6097c6cc88..edd1497d9e 100644 --- a/src/strings/clone.go +++ b/src/strings/clone.go @@ -16,7 +16,12 @@ import ( // overuse of Clone can make programs use more memory. // Clone should typically be used only rarely, and only when // profiling indicates that it is needed. +// For strings of length zero the string "" will be returned +// and no allocation is made. func Clone(s string) string { + if len(s) == 0 { + return "" + } b := make([]byte, len(s)) copy(b, s) return *(*string)(unsafe.Pointer(&b)) diff --git a/src/strings/clone_test.go b/src/strings/clone_test.go index 5396771047..a9ba8add23 100644 --- a/src/strings/clone_test.go +++ b/src/strings/clone_test.go @@ -11,9 +11,13 @@ import ( "unsafe" ) +var emptyString string + func TestClone(t *testing.T) { var cloneTests = []string{ "", + strings.Clone(""), + strings.Repeat("a", 42)[:0], "short", strings.Repeat("a", 42), } @@ -25,9 +29,14 @@ func TestClone(t *testing.T) { inputHeader := (*reflect.StringHeader)(unsafe.Pointer(&input)) cloneHeader := (*reflect.StringHeader)(unsafe.Pointer(&clone)) - if inputHeader.Data == cloneHeader.Data { + if len(input) != 0 && cloneHeader.Data == inputHeader.Data { t.Errorf("Clone(%q) return value should not reference inputs backing memory.", input) } + + emptyHeader := (*reflect.StringHeader)(unsafe.Pointer(&emptyString)) + if len(input) == 0 && cloneHeader.Data != emptyHeader.Data { + t.Errorf("Clone(%#v) return value should be equal to empty string.", inputHeader) + } } } -- 2.50.0