diff options
Diffstat (limited to 'src/pkg/bytes/buffer.go')
-rw-r--r-- | src/pkg/bytes/buffer.go | 78 |
1 files changed, 64 insertions, 14 deletions
diff --git a/src/pkg/bytes/buffer.go b/src/pkg/bytes/buffer.go index 01e6aef67..2574b4f43 100644 --- a/src/pkg/bytes/buffer.go +++ b/src/pkg/bytes/buffer.go @@ -12,14 +12,6 @@ import ( "utf8" ) -// Copy from string to byte array at offset doff. Assume there's room. -func copyString(dst []byte, doff int, str string) { - for soff := 0; soff < len(str); soff++ { - dst[doff] = str[soff] - doff++ - } -} - // 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 { @@ -27,8 +19,20 @@ type Buffer struct { off int // read at &buf[off], write at &buf[len(buf)] runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune bootstrap [64]byte // memory to hold first slice; helps small buffers (Printf) avoid allocation. + lastRead readOp // last read operation, so that Unread* can work correctly. } +// The readOp constants describe the last action performed on +// the buffer, so that UnreadRune and UnreadByte can +// check for invalid usage. +type readOp int + +const ( + opInvalid readOp = iota // Non-read operation. + opReadRune // Read rune. + opRead // Any other read operation. +) + // Bytes returns a slice of the contents of the unread portion of the buffer; // len(b.Bytes()) == b.Len(). If the caller changes the contents of the // returned slice, the contents of the buffer will change provided there @@ -52,6 +56,7 @@ func (b *Buffer) Len() int { return len(b.buf) - b.off } // Truncate discards all but the first n unread bytes from the buffer. // It is an error to call b.Truncate(n) with n > b.Len(). func (b *Buffer) Truncate(n int) { + b.lastRead = opInvalid if n == 0 { // Reuse buffer space. b.off = 0 @@ -90,6 +95,7 @@ func (b *Buffer) grow(n int) int { // Write appends the contents of p to the buffer. The return // value n is the length of p; err is always nil. func (b *Buffer) Write(p []byte) (n int, err os.Error) { + b.lastRead = opInvalid m := b.grow(len(p)) copy(b.buf[m:], p) return len(p), nil @@ -98,9 +104,9 @@ func (b *Buffer) Write(p []byte) (n int, err os.Error) { // WriteString appends the contents of s to the buffer. The return // value n is the length of s; err is always nil. func (b *Buffer) WriteString(s string) (n int, err os.Error) { + b.lastRead = opInvalid m := b.grow(len(s)) - copyString(b.buf, m, s) - return len(s), nil + return copy(b.buf[m:], s), nil } // MinRead is the minimum slice size passed to a Read call by @@ -114,6 +120,7 @@ const MinRead = 512 // Any error except os.EOF encountered during the read // is also returned. func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) { + b.lastRead = opInvalid // If buffer is empty, reset to recover space. if b.off >= len(b.buf) { b.Truncate(0) @@ -150,6 +157,7 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) { // occurs. The return value n is the number of bytes written. // Any error encountered during the write is also returned. func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) { + b.lastRead = opInvalid for b.off < len(b.buf) { m, e := w.Write(b.buf[b.off:]) n += int64(m) @@ -167,6 +175,7 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) { // The returned error is always nil, but is included // to match bufio.Writer's WriteByte. func (b *Buffer) WriteByte(c byte) os.Error { + b.lastRead = opInvalid m := b.grow(1) b.buf[m] = c return nil @@ -181,7 +190,7 @@ func (b *Buffer) WriteRune(r int) (n int, err os.Error) { b.WriteByte(byte(r)) return 1, nil } - n = utf8.EncodeRune(r, b.runeBytes[0:]) + n = utf8.EncodeRune(b.runeBytes[0:], r) b.Write(b.runeBytes[0:n]) return n, nil } @@ -191,6 +200,7 @@ func (b *Buffer) WriteRune(r int) (n int, err os.Error) { // buffer has no data to return, err is os.EOF even if len(p) is zero; // otherwise it is nil. func (b *Buffer) Read(p []byte) (n int, err os.Error) { + b.lastRead = opInvalid if b.off >= len(b.buf) { // Buffer is empty, reset to recover space. b.Truncate(0) @@ -198,6 +208,9 @@ func (b *Buffer) Read(p []byte) (n int, err os.Error) { } n = copy(p, b.buf[b.off:]) b.off += n + if n > 0 { + b.lastRead = opRead + } return } @@ -206,18 +219,23 @@ func (b *Buffer) Read(p []byte) (n int, err os.Error) { // If there are fewer than n bytes in the buffer, Next returns the entire buffer. // The slice is only valid until the next call to a read or write method. func (b *Buffer) Next(n int) []byte { + b.lastRead = opInvalid m := b.Len() if n > m { n = m } data := b.buf[b.off : b.off+n] b.off += n + if n > 0 { + b.lastRead = opRead + } return data } // ReadByte reads and returns the next byte from the buffer. // If no byte is available, it returns error os.EOF. func (b *Buffer) ReadByte() (c byte, err os.Error) { + b.lastRead = opInvalid if b.off >= len(b.buf) { // Buffer is empty, reset to recover space. b.Truncate(0) @@ -225,6 +243,7 @@ func (b *Buffer) ReadByte() (c byte, err os.Error) { } c = b.buf[b.off] b.off++ + b.lastRead = opRead return c, nil } @@ -234,11 +253,13 @@ func (b *Buffer) ReadByte() (c byte, err os.Error) { // If the bytes are an erroneous UTF-8 encoding, it // consumes one byte and returns U+FFFD, 1. func (b *Buffer) ReadRune() (r int, size int, err os.Error) { + b.lastRead = opInvalid if b.off >= len(b.buf) { // Buffer is empty, reset to recover space. b.Truncate(0) return 0, 0, os.EOF } + b.lastRead = opReadRune c := b.buf[b.off] if c < utf8.RuneSelf { b.off++ @@ -249,6 +270,37 @@ func (b *Buffer) ReadRune() (r int, size int, err os.Error) { return r, n, nil } +// 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 +// it is stricter than UnreadByte, which will unread the last byte +// from any read operation.) +func (b *Buffer) UnreadRune() os.Error { + if b.lastRead != opReadRune { + return os.ErrorString("bytes.Buffer: UnreadRune: previous operation was not ReadRune") + } + b.lastRead = opInvalid + if b.off > 0 { + _, n := utf8.DecodeLastRune(b.buf[0:b.off]) + b.off -= n + } + 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. +func (b *Buffer) UnreadByte() os.Error { + if b.lastRead != opReadRune && b.lastRead != opRead { + return os.ErrorString("bytes.Buffer: UnreadByte: previous operation was not a read") + } + b.lastRead = opInvalid + if b.off > 0 { + b.off-- + } + return nil +} + // 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 to size the internal buffer for writing. To do that, @@ -259,7 +311,5 @@ func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} } // initial contents. It is intended to prepare a buffer to read an existing // string. func NewBufferString(s string) *Buffer { - buf := make([]byte, len(s)) - copyString(buf, 0, s) - return &Buffer{buf: buf} + return &Buffer{buf: []byte(s)} } |