]> Cypherpunks repositories - gostls13.git/commitdiff
strings: align Clone output with string([]byte(""))
authorMartin Möhrmann <martin@golang.org>
Mon, 1 Nov 2021 05:42:01 +0000 (06:42 +0100)
committerMartin Möhrmann <martin@golang.org>
Mon, 1 Nov 2021 14:45:28 +0000 (14:45 +0000)
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 <martin@golang.org>
Run-TryBot: Martin Möhrmann <martin@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
src/strings/clone.go
src/strings/clone_test.go

index 6097c6cc88ef39194e59e85ca93acdd469903835..edd1497d9e58811add83d1fd72378912a5396e87 100644 (file)
@@ -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))
index 539677104763191427e68fb1eba02c41f9aba9e2..a9ba8add2355245a532f57b7cefa93998b3ee4fa 100644 (file)
@@ -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)
+               }
        }
 }