mirror of
https://github.com/golang/go
synced 2024-11-23 10:30:03 -07:00
runtime: introduce nextslicecap
This allows to reuse the slice cap computation across specialized growslice funcs. Updates #49480 Change-Id: Ie075d9c3075659ea14c11d51a9cd4ed46aa0e961 Reviewed-on: https://go-review.googlesource.com/c/go/+/495876 Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Egon Elbre <egonelbre@gmail.com> Reviewed-by: Keith Randall <khr@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
c56f463412
commit
1d84b02b22
@ -51,6 +51,7 @@ func TestIntendedInlining(t *testing.T) {
|
||||
"getMCache",
|
||||
"isDirectIface",
|
||||
"itabHashFunc",
|
||||
"nextslicecap",
|
||||
"noescape",
|
||||
"pcvalueCacheKey",
|
||||
"readUnaligned32",
|
||||
|
@ -177,37 +177,7 @@ func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice
|
||||
return slice{unsafe.Pointer(&zerobase), newLen, newLen}
|
||||
}
|
||||
|
||||
newcap := oldCap
|
||||
doublecap := newcap + newcap
|
||||
if newLen > doublecap {
|
||||
newcap = newLen
|
||||
} else {
|
||||
const threshold = 256
|
||||
if oldCap < threshold {
|
||||
newcap = doublecap
|
||||
} else {
|
||||
for {
|
||||
// Transition from growing 2x for small slices
|
||||
// to growing 1.25x for large slices. This formula
|
||||
// gives a smooth-ish transition between the two.
|
||||
newcap += (newcap + 3*threshold) >> 2
|
||||
|
||||
// We need to check `newcap >= newLen` and whether `newcap` overflowed.
|
||||
// newLen is guaranteed to be larger than zero, hence
|
||||
// when newcap overflows then `uint(newcap) > uint(newLen)`.
|
||||
// This allows to check for both with the same comparison.
|
||||
if uint(newcap) >= uint(newLen) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Set newcap to the requested cap when
|
||||
// the newcap calculation overflowed.
|
||||
if newcap <= 0 {
|
||||
newcap = newLen
|
||||
}
|
||||
}
|
||||
}
|
||||
newcap := nextslicecap(newLen, oldCap)
|
||||
|
||||
var overflow bool
|
||||
var lenmem, newlenmem, capmem uintptr
|
||||
@ -290,6 +260,41 @@ func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice
|
||||
return slice{p, newLen, newcap}
|
||||
}
|
||||
|
||||
// nextslicecap computes the next appropriate slice length.
|
||||
func nextslicecap(newLen, oldCap int) int {
|
||||
newcap := oldCap
|
||||
doublecap := newcap + newcap
|
||||
if newLen > doublecap {
|
||||
return newLen
|
||||
}
|
||||
|
||||
const threshold = 256
|
||||
if oldCap < threshold {
|
||||
return doublecap
|
||||
}
|
||||
for {
|
||||
// Transition from growing 2x for small slices
|
||||
// to growing 1.25x for large slices. This formula
|
||||
// gives a smooth-ish transition between the two.
|
||||
newcap += (newcap + 3*threshold) >> 2
|
||||
|
||||
// We need to check `newcap >= newLen` and whether `newcap` overflowed.
|
||||
// newLen is guaranteed to be larger than zero, hence
|
||||
// when newcap overflows then `uint(newcap) > uint(newLen)`.
|
||||
// This allows to check for both with the same comparison.
|
||||
if uint(newcap) >= uint(newLen) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Set newcap to the requested cap when
|
||||
// the newcap calculation overflowed.
|
||||
if newcap <= 0 {
|
||||
return newLen
|
||||
}
|
||||
return newcap
|
||||
}
|
||||
|
||||
//go:linkname reflect_growslice reflect.growslice
|
||||
func reflect_growslice(et *_type, old slice, num int) slice {
|
||||
// Semantically equivalent to slices.Grow, except that the caller
|
||||
|
Loading…
Reference in New Issue
Block a user