diff options
author | Ian Lance Taylor <iant@golang.org> | 2017-09-14 17:11:35 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2017-09-14 17:11:35 +0000 |
commit | bc998d034f45d1828a8663b2eed928faf22a7d01 (patch) | |
tree | 8d262a22ca7318f4bcd64269fe8fe9e45bcf8d0f /libgo/go/bytes/buffer.go | |
parent | a41a6142df74219f596e612d3a7775f68ca6e96f (diff) | |
download | gcc-bc998d034f45d1828a8663b2eed928faf22a7d01.zip gcc-bc998d034f45d1828a8663b2eed928faf22a7d01.tar.gz gcc-bc998d034f45d1828a8663b2eed928faf22a7d01.tar.bz2 |
libgo: update to go1.9
Reviewed-on: https://go-review.googlesource.com/63753
From-SVN: r252767
Diffstat (limited to 'libgo/go/bytes/buffer.go')
-rw-r--r-- | libgo/go/bytes/buffer.go | 137 |
1 files changed, 88 insertions, 49 deletions
diff --git a/libgo/go/bytes/buffer.go b/libgo/go/bytes/buffer.go index 196419d..20e42bb 100644 --- a/libgo/go/bytes/buffer.go +++ b/libgo/go/bytes/buffer.go @@ -15,10 +15,15 @@ import ( // A Buffer is a variable-sized buffer of bytes with Read and Write methods. // The zero value for Buffer is an empty buffer ready to use. type Buffer struct { - buf []byte // contents are the bytes buf[off : len(buf)] - off int // read at &buf[off], write at &buf[len(buf)] - bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation. - lastRead readOp // last read operation, so that Unread* can work correctly. + buf []byte // contents are the bytes buf[off : len(buf)] + off int // read at &buf[off], write at &buf[len(buf)] + lastRead readOp // last read operation, so that Unread* can work correctly. + // FIXME: lastRead can fit in a single byte + + // memory to hold first slice; helps small buffers avoid allocation. + // FIXME: it would be advisable to align Buffer to cachelines to avoid false + // sharing. + bootstrap [64]byte } // The readOp constants describe the last action performed on @@ -68,13 +73,13 @@ func (b *Buffer) Cap() int { return cap(b.buf) } // but continues to use the same allocated storage. // It panics if n is negative or greater than the length of the buffer. func (b *Buffer) Truncate(n int) { + if n == 0 { + b.Reset() + return + } b.lastRead = opInvalid - switch { - case n < 0 || n > b.Len(): + if n < 0 || n > b.Len() { panic("bytes.Buffer: truncation out of range") - case n == 0: - // Reuse buffer space. - b.off = 0 } b.buf = b.buf[0 : b.off+n] } @@ -82,7 +87,22 @@ func (b *Buffer) Truncate(n int) { // Reset resets the buffer to be empty, // but it retains the underlying storage for use by future writes. // Reset is the same as Truncate(0). -func (b *Buffer) Reset() { b.Truncate(0) } +func (b *Buffer) Reset() { + b.buf = b.buf[:0] + b.off = 0 + b.lastRead = opInvalid +} + +// tryGrowByReslice is a inlineable version of grow for the fast-case where the +// internal buffer only needs to be resliced. +// It returns the index where bytes should be written and whether it succeeded. +func (b *Buffer) tryGrowByReslice(n int) (int, bool) { + if l := len(b.buf); l+n <= cap(b.buf) { + b.buf = b.buf[:l+n] + return l, true + } + return 0, false +} // grow grows the buffer to guarantee space for n more bytes. // It returns the index where bytes should be written. @@ -91,29 +111,33 @@ func (b *Buffer) grow(n int) int { m := b.Len() // If buffer is empty, reset to recover space. if m == 0 && b.off != 0 { - b.Truncate(0) + b.Reset() } - if len(b.buf)+n > cap(b.buf) { - var buf []byte - if b.buf == nil && n <= len(b.bootstrap) { - buf = b.bootstrap[0:] - } else if m+n <= cap(b.buf)/2 { - // We can slide things down instead of allocating a new - // slice. We only need m+n <= cap(b.buf) to slide, but - // we instead let capacity get twice as large so we - // don't spend all our time copying. - copy(b.buf[:], b.buf[b.off:]) - buf = b.buf[:m] - } else { - // not enough space anywhere - buf = makeSlice(2*cap(b.buf) + n) - copy(buf, b.buf[b.off:]) - } + // Try to grow by means of a reslice. + if i, ok := b.tryGrowByReslice(n); ok { + return i + } + // Check if we can make use of bootstrap array. + if b.buf == nil && n <= len(b.bootstrap) { + b.buf = b.bootstrap[:n] + return 0 + } + if m+n <= cap(b.buf)/2 { + // We can slide things down instead of allocating a new + // slice. We only need m+n <= cap(b.buf) to slide, but + // we instead let capacity get twice as large so we + // don't spend all our time copying. + copy(b.buf[:], b.buf[b.off:]) + } else { + // Not enough space anywhere, we need to allocate. + buf := makeSlice(2*cap(b.buf) + n) + copy(buf, b.buf[b.off:]) b.buf = buf - b.off = 0 } - b.buf = b.buf[0 : b.off+m+n] - return b.off + m + // Restore b.off and len(b.buf). + b.off = 0 + b.buf = b.buf[:m+n] + return m } // Grow grows the buffer's capacity, if necessary, to guarantee space for @@ -134,7 +158,10 @@ func (b *Buffer) Grow(n int) { // buffer becomes too large, Write will panic with ErrTooLarge. func (b *Buffer) Write(p []byte) (n int, err error) { b.lastRead = opInvalid - m := b.grow(len(p)) + m, ok := b.tryGrowByReslice(len(p)) + if !ok { + m = b.grow(len(p)) + } return copy(b.buf[m:], p), nil } @@ -143,7 +170,10 @@ func (b *Buffer) Write(p []byte) (n int, err error) { // buffer becomes too large, WriteString will panic with ErrTooLarge. func (b *Buffer) WriteString(s string) (n int, err error) { b.lastRead = opInvalid - m := b.grow(len(s)) + m, ok := b.tryGrowByReslice(len(s)) + if !ok { + m = b.grow(len(s)) + } return copy(b.buf[m:], s), nil } @@ -161,7 +191,7 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) { b.lastRead = opInvalid // If buffer is empty, reset to recover space. if b.off >= len(b.buf) { - b.Truncate(0) + b.Reset() } for { if free := cap(b.buf) - len(b.buf); free < MinRead { @@ -225,7 +255,7 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) { } } // Buffer is now empty; reset. - b.Truncate(0) + b.Reset() return } @@ -235,7 +265,10 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) { // ErrTooLarge. func (b *Buffer) WriteByte(c byte) error { b.lastRead = opInvalid - m := b.grow(1) + m, ok := b.tryGrowByReslice(1) + if !ok { + m = b.grow(1) + } b.buf[m] = c return nil } @@ -250,7 +283,10 @@ func (b *Buffer) WriteRune(r rune) (n int, err error) { return 1, nil } b.lastRead = opInvalid - m := b.grow(utf8.UTFMax) + m, ok := b.tryGrowByReslice(utf8.UTFMax) + if !ok { + m = b.grow(utf8.UTFMax) + } n = utf8.EncodeRune(b.buf[m:m+utf8.UTFMax], r) b.buf = b.buf[:m+n] return n, nil @@ -264,7 +300,7 @@ func (b *Buffer) Read(p []byte) (n int, err error) { b.lastRead = opInvalid if b.off >= len(b.buf) { // Buffer is empty, reset to recover space. - b.Truncate(0) + b.Reset() if len(p) == 0 { return } @@ -302,7 +338,7 @@ func (b *Buffer) ReadByte() (byte, error) { b.lastRead = opInvalid if b.off >= len(b.buf) { // Buffer is empty, reset to recover space. - b.Truncate(0) + b.Reset() return 0, io.EOF } c := b.buf[b.off] @@ -320,7 +356,7 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) { b.lastRead = opInvalid if b.off >= len(b.buf) { // Buffer is empty, reset to recover space. - b.Truncate(0) + b.Reset() return 0, 0, io.EOF } c := b.buf[b.off] @@ -337,12 +373,12 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) { // UnreadRune unreads the last rune returned by ReadRune. // If the most recent read or write operation on the buffer was -// not a ReadRune, UnreadRune returns an error. (In this regard +// not a successful ReadRune, UnreadRune returns an error. (In this regard // it is stricter than UnreadByte, which will unread the last byte // from any read operation.) func (b *Buffer) UnreadRune() error { if b.lastRead <= opInvalid { - return errors.New("bytes.Buffer: UnreadRune: previous operation was not ReadRune") + return errors.New("bytes.Buffer: UnreadRune: previous operation was not a successful ReadRune") } if b.off >= int(b.lastRead) { b.off -= int(b.lastRead) @@ -351,12 +387,13 @@ func (b *Buffer) UnreadRune() error { return nil } -// UnreadByte unreads the last byte returned by the most recent -// read operation. If write has happened since the last read, UnreadByte -// returns an error. +// UnreadByte unreads the last byte returned by the most recent successful +// read operation that read at least one byte. If a write has happened since +// the last read, if the last read returned an error, or if the read read zero +// bytes, UnreadByte returns an error. func (b *Buffer) UnreadByte() error { if b.lastRead == opInvalid { - return errors.New("bytes.Buffer: UnreadByte: previous operation was not a read") + return errors.New("bytes.Buffer: UnreadByte: previous operation was not a successful read") } b.lastRead = opInvalid if b.off > 0 { @@ -404,10 +441,12 @@ func (b *Buffer) ReadString(delim byte) (line string, err error) { return string(slice), err } -// NewBuffer creates and initializes a new Buffer using buf as its initial -// contents. It is intended to prepare a Buffer to read existing data. It -// can also be used to size the internal buffer for writing. To do that, -// buf should have the desired capacity but a length of zero. +// NewBuffer creates and initializes a new Buffer using buf as its +// initial contents. The new Buffer takes ownership of buf, and the +// caller should not use buf after this call. NewBuffer is intended to +// prepare a Buffer to read existing data. It can also be used to size +// the internal buffer for writing. To do that, buf should have the +// desired capacity but a length of zero. // // In most cases, new(Buffer) (or just declaring a Buffer variable) is // sufficient to initialize a Buffer. |