]> Cypherpunks repositories - gostls13.git/commitdiff
strings: add Clone function
authorMartin Möhrmann <martin@golang.org>
Sat, 28 Aug 2021 15:54:10 +0000 (17:54 +0200)
committerMartin Möhrmann <martin@golang.org>
Mon, 13 Sep 2021 18:02:42 +0000 (18:02 +0000)
The new strings.Clone function copies the input string
without the returned cloned string referencing the
input strings memory.

goarch: amd64
cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz

name     time/op
Clone-8  24.2ns ± 2%

name     alloc/op
Clone-8   48.0B ± 0%

name     allocs/op
Clone-8    1.00 ± 0%

Update #45038
Fixes #40200

Change-Id: Id9116c21c14328ec3931ef9a67a2e4f30ff301f9
Reviewed-on: https://go-review.googlesource.com/c/go/+/345849
Trust: Martin Möhrmann <martin@golang.org>
Run-TryBot: Martin Möhrmann <martin@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Joe Tsai <joetsai@digital-static.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/strings/clone.go [new file with mode: 0644]
src/strings/clone_test.go [new file with mode: 0644]

diff --git a/src/strings/clone.go b/src/strings/clone.go
new file mode 100644 (file)
index 0000000..6097c6c
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strings
+
+import (
+       "unsafe"
+)
+
+// Clone returns a fresh copy of s.
+// It guarantees to make a copy of s into a new allocation,
+// which can be important when retaining only a small substring
+// of a much larger string. Using Clone can help such programs
+// use less memory. Of course, since using Clone makes a copy,
+// 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.
+func Clone(s string) string {
+       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
new file mode 100644 (file)
index 0000000..5396771
--- /dev/null
@@ -0,0 +1,40 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.ß
+
+package strings_test
+
+import (
+       "reflect"
+       "strings"
+       "testing"
+       "unsafe"
+)
+
+func TestClone(t *testing.T) {
+       var cloneTests = []string{
+               "",
+               "short",
+               strings.Repeat("a", 42),
+       }
+       for _, input := range cloneTests {
+               clone := strings.Clone(input)
+               if clone != input {
+                       t.Errorf("Clone(%q) = %q; want %q", input, clone, input)
+               }
+
+               inputHeader := (*reflect.StringHeader)(unsafe.Pointer(&input))
+               cloneHeader := (*reflect.StringHeader)(unsafe.Pointer(&clone))
+               if inputHeader.Data == cloneHeader.Data {
+                       t.Errorf("Clone(%q) return value should not reference inputs backing memory.", input)
+               }
+       }
+}
+
+func BenchmarkClone(b *testing.B) {
+       var str = strings.Repeat("a", 42)
+       b.ReportAllocs()
+       for i := 0; i < b.N; i++ {
+               stringSink = strings.Clone(str)
+       }
+}