1
0
mirror of https://github.com/golang/go synced 2024-11-26 05:37:57 -07:00

strings: make use of sizeclasses in (*Builder).Grow

Fixes #64833

Change-Id: Ice3f5dfab65f5525bc7a6f57ddeaabda8d64dfa3
GitHub-Last-Rev: 38f1d6c19d
GitHub-Pull-Request: golang/go#64835
Reviewed-on: https://go-review.googlesource.com/c/go/+/552135
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Mateusz Poliwczak 2024-02-02 15:54:24 +00:00 committed by Keith Randall
parent cf52e70997
commit 968b71bce4
5 changed files with 26 additions and 7 deletions

View File

@ -525,7 +525,7 @@ func Join(s [][]byte, sep []byte) []byte {
n += len(v)
}
b := bytealg.MakeNoZero(n)
b := bytealg.MakeNoZero(n)[:n:n]
bp := copy(b, s[0])
for _, v := range s[1:] {
bp += copy(b[bp:], sep)
@ -610,7 +610,7 @@ func Repeat(b []byte, count int) []byte {
chunkMax = len(b)
}
}
nb := bytealg.MakeNoZero(n)
nb := bytealg.MakeNoZero(n)[:n:n]
bp := copy(nb, b)
for bp < n {
chunk := bp
@ -640,7 +640,7 @@ func ToUpper(s []byte) []byte {
// Just return a copy.
return append([]byte(""), s...)
}
b := bytealg.MakeNoZero(len(s))
b := bytealg.MakeNoZero(len(s))[:len(s):len(s)]
for i := 0; i < len(s); i++ {
c := s[i]
if 'a' <= c && c <= 'z' {
@ -670,7 +670,7 @@ func ToLower(s []byte) []byte {
if !hasUpper {
return append([]byte(""), s...)
}
b := bytealg.MakeNoZero(len(s))
b := bytealg.MakeNoZero(len(s))[:len(s):len(s)]
for i := 0; i < len(s); i++ {
c := s[i]
if 'A' <= c && c <= 'Z' {

View File

@ -111,7 +111,8 @@ func LastIndexRabinKarp[T string | []byte](s, sep T) int {
return -1
}
// MakeNoZero makes a slice of length and capacity n without zeroing the bytes.
// MakeNoZero makes a slice of length n and capacity of at least n Bytes
// without zeroing the bytes (including the bytes between len and cap).
// It is the caller's responsibility to ensure uninitialized bytes
// do not leak to the end user.
func MakeNoZero(n int) []byte

View File

@ -366,5 +366,6 @@ func bytealg_MakeNoZero(len int) []byte {
if uintptr(len) > maxAlloc {
panicmakeslicelen()
}
return unsafe.Slice((*byte)(mallocgc(uintptr(len), nil, false)), len)
cap := roundupsize(uintptr(len), true)
return unsafe.Slice((*byte)(mallocgc(uintptr(cap), nil, false)), cap)[:len]
}

View File

@ -15,6 +15,10 @@ import (
// Do not copy a non-zero Builder.
type Builder struct {
addr *Builder // of receiver, to detect copies by value
// External users should never get direct access to this buffer, since
// the slice at some point will be converted to a string using unsafe, also
// data between len(buf) and cap(buf) might be uninitialized.
buf []byte
}

View File

@ -385,3 +385,16 @@ func BenchmarkBuildString_ByteBuffer(b *testing.B) {
}
})
}
func TestBuilderGrowSizeclasses(t *testing.T) {
s := Repeat("a", 19)
allocs := testing.AllocsPerRun(100, func() {
var b Builder
b.Grow(18)
b.WriteString(s)
_ = b.String()
})
if allocs > 1 {
t.Fatalf("unexpected amount of allocations: %v, want: 1", allocs)
}
}