diff options
| author | Egon Elbre <egonelbre@gmail.com> | 2023-05-17 17:33:15 +0300 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2023-09-04 17:50:50 +0000 |
| commit | 1d84b02b228cbd35660e168d26fd2801daed08fe (patch) | |
| tree | 39a5439598a3cb6481c2365654c3b0f9f3cb683f /src/runtime | |
| parent | c56f463412428f8a4d06bf67da9059b389c8d526 (diff) | |
| download | go-1d84b02b228cbd35660e168d26fd2801daed08fe.tar.xz | |
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>
Diffstat (limited to 'src/runtime')
| -rw-r--r-- | src/runtime/slice.go | 67 |
1 files changed, 36 insertions, 31 deletions
diff --git a/src/runtime/slice.go b/src/runtime/slice.go index 29e2fd5cbd..a7d5769f47 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -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 |
