aboutsummaryrefslogtreecommitdiff
path: root/src/bytes/buffer.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/bytes/buffer.go')
-rw-r--r--src/bytes/buffer.go31
1 files changed, 22 insertions, 9 deletions
diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go
index 549b077708..0bacbda164 100644
--- a/src/bytes/buffer.go
+++ b/src/bytes/buffer.go
@@ -138,10 +138,8 @@ func (b *Buffer) grow(n int) int {
} else if c > maxInt-c-n {
panic(ErrTooLarge)
} else {
- // Not enough space anywhere, we need to allocate.
- buf := makeSlice(2*c + n)
- copy(buf, b.buf[b.off:])
- b.buf = buf
+ // Add b.off to account for b.buf[:b.off] being sliced off the front.
+ b.buf = growSlice(b.buf[b.off:], b.off+n)
}
// Restore b.off and len(b.buf).
b.off = 0
@@ -217,16 +215,31 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
}
}
-// makeSlice allocates a slice of size n. If the allocation fails, it panics
-// with ErrTooLarge.
-func makeSlice(n int) []byte {
- // If the make fails, give a known error.
+// growSlice grows b by n, preserving the original content of b.
+// If the allocation fails, it panics with ErrTooLarge.
+func growSlice(b []byte, n int) []byte {
defer func() {
if recover() != nil {
panic(ErrTooLarge)
}
}()
- return make([]byte, n)
+ // TODO(http://golang.org/issue/51462): We should rely on the append-make
+ // pattern so that the compiler can call runtime.growslice. For example:
+ // return append(b, make([]byte, n)...)
+ // This avoids unnecessary zero-ing of the first len(b) bytes of the
+ // allocated slice, but this pattern causes b to escape onto the heap.
+ //
+ // Instead use the append-make pattern with a nil slice to ensure that
+ // we allocate buffers rounded up to the closest size class.
+ c := len(b) + n // ensure enough space for n elements
+ if c < 2*cap(b) {
+ // The growth rate has historically always been 2x. In the future,
+ // we could rely purely on append to determine the growth rate.
+ c = 2 * cap(b)
+ }
+ b2 := append([]byte(nil), make([]byte, c)...)
+ copy(b2, b)
+ return b2[:len(b)]
}
// WriteTo writes data to w until the buffer is drained or an error occurs.