Skip to content

Commit e74e363

Browse files
author
Martin Möhrmann
committed
strings: add Clone function
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 <[email protected]> Run-TryBot: Martin Möhrmann <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Joe Tsai <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent bced369 commit e74e363

File tree

2 files changed

+63
-0
lines changed

2 files changed

+63
-0
lines changed

src/strings/clone.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package strings
6+
7+
import (
8+
"unsafe"
9+
)
10+
11+
// Clone returns a fresh copy of s.
12+
// It guarantees to make a copy of s into a new allocation,
13+
// which can be important when retaining only a small substring
14+
// of a much larger string. Using Clone can help such programs
15+
// use less memory. Of course, since using Clone makes a copy,
16+
// overuse of Clone can make programs use more memory.
17+
// Clone should typically be used only rarely, and only when
18+
// profiling indicates that it is needed.
19+
func Clone(s string) string {
20+
b := make([]byte, len(s))
21+
copy(b, s)
22+
return *(*string)(unsafe.Pointer(&b))
23+
}

src/strings/clone_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.ß
4+
5+
package strings_test
6+
7+
import (
8+
"reflect"
9+
"strings"
10+
"testing"
11+
"unsafe"
12+
)
13+
14+
func TestClone(t *testing.T) {
15+
var cloneTests = []string{
16+
"",
17+
"short",
18+
strings.Repeat("a", 42),
19+
}
20+
for _, input := range cloneTests {
21+
clone := strings.Clone(input)
22+
if clone != input {
23+
t.Errorf("Clone(%q) = %q; want %q", input, clone, input)
24+
}
25+
26+
inputHeader := (*reflect.StringHeader)(unsafe.Pointer(&input))
27+
cloneHeader := (*reflect.StringHeader)(unsafe.Pointer(&clone))
28+
if inputHeader.Data == cloneHeader.Data {
29+
t.Errorf("Clone(%q) return value should not reference inputs backing memory.", input)
30+
}
31+
}
32+
}
33+
34+
func BenchmarkClone(b *testing.B) {
35+
var str = strings.Repeat("a", 42)
36+
b.ReportAllocs()
37+
for i := 0; i < b.N; i++ {
38+
stringSink = strings.Clone(str)
39+
}
40+
}

0 commit comments

Comments
 (0)