Skip to content

Commit 0669c38

Browse files
committed
slices: change implementation for Clone()
Change the implementation of slices Clone. It's 28% faster on my laptop. As discussed in #57433 (comment), no extra issue is needed for this simple fix. goos: darwin goarch: arm64 pkg: github.com/David-Mao/Euclid/Go/utils │ old.txt │ new.txt │ │ sec/op │ sec/op vs base │ Clone-12 16.95n ± 1% 12.06n ± 2% -28.85% (p=0.000 n=10)
1 parent 3fce111 commit 0669c38

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

src/slices/slices.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,9 @@ func Clone[S ~[]E, E any](s S) S {
340340
if s == nil {
341341
return nil
342342
}
343-
return append(S([]E{}), s...)
343+
t := make([]E, len(s))
344+
copy(t, s)
345+
return t
344346
}
345347

346348
// Compact replaces consecutive runs of equal elements with a single copy.

src/slices/slices_benchmark_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2023 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 slices
6+
7+
import (
8+
"testing"
9+
)
10+
11+
var sink any = nil
12+
13+
func BenchmarkIntClone_10B(b *testing.B) {
14+
benchmarkClone[int](b, 10)
15+
}
16+
17+
func BenchmarkIntClone_1Kb(b *testing.B) {
18+
benchmarkClone[int](b, 1<<10)
19+
}
20+
21+
func BenchmarkIntClone_10Kb(b *testing.B) {
22+
benchmarkClone[int](b, 10<<10)
23+
}
24+
25+
func BenchmarkIntClone_1Mb(b *testing.B) {
26+
benchmarkClone[int](b, 1<<20)
27+
}
28+
29+
func BenchmarkIntClone_10Mb(b *testing.B) {
30+
benchmarkClone[int](b, 10<<20)
31+
}
32+
33+
func BenchmarkByteClone_10B(b *testing.B) {
34+
benchmarkClone[byte](b, 10)
35+
}
36+
37+
func BenchmarkByteClone_10Kb(b *testing.B) {
38+
benchmarkClone[byte](b, 10<<10)
39+
}
40+
41+
func benchmarkClone[T int | byte](b *testing.B, n int) {
42+
s1 := make([]T, n)
43+
for i := 0; i < n/2; i++ {
44+
s1[i] = T(i)
45+
s1[n-i-1] = T(i * 2)
46+
}
47+
b.ResetTimer()
48+
b.ReportAllocs()
49+
for i := 0; i < b.N; i++ {
50+
sink = Clone(s1)
51+
}
52+
if sink == nil {
53+
b.Fatal("Benchmark did not run!")
54+
}
55+
sink = nil
56+
}

0 commit comments

Comments
 (0)