]> Cypherpunks repositories - gostls13.git/commitdiff
bufio: introduce Peek.
authorNigel Tao <nigeltao@golang.org>
Tue, 3 Aug 2010 23:44:02 +0000 (09:44 +1000)
committerNigel Tao <nigeltao@golang.org>
Tue, 3 Aug 2010 23:44:02 +0000 (09:44 +1000)
I'll leave whether or not this obsoletes UnreadByte for a future CL.

R=r, rsc
CC=golang-dev
https://golang.org/cl/1912042

src/pkg/bufio/bufio.go
src/pkg/bufio/bufio_test.go

index e73f082890eb7680f11a15e467d52388acac782c..37bdea274a6395e274f3f0e804a871f626121d8a 100644 (file)
@@ -28,6 +28,7 @@ type Error struct {
 var (
        ErrInvalidUnreadByte os.Error = &Error{"bufio: invalid use of UnreadByte"}
        ErrBufferFull        os.Error = &Error{"bufio: buffer full"}
+       ErrNegativeCount     os.Error = &Error{"bufio: negative count"}
        errInternal          os.Error = &Error{"bufio: internal error"}
 )
 
@@ -83,13 +84,11 @@ func NewReader(rd io.Reader) *Reader {
 // fill reads a new chunk into the buffer.
 func (b *Reader) fill() {
        // Slide existing data to beginning.
-       if b.w > b.r {
-               copy(b.buf[0:b.w-b.r], b.buf[b.r:b.w])
+       if b.r > 0 {
+               copy(b.buf, b.buf[b.r:b.w])
                b.w -= b.r
-       } else {
-               b.w = 0
+               b.r = 0
        }
-       b.r = 0
 
        // Read new data.
        n, e := b.rd.Read(b.buf[b.w:])
@@ -99,6 +98,31 @@ func (b *Reader) fill() {
        }
 }
 
+// Peek returns the next n bytes without advancing the reader. The bytes stop
+// being valid at the next read call. If Peek returns fewer than n bytes, it
+// also returns an error explaining why the read is short. The error is
+// ErrBufferFull if n is larger than b's buffer size.
+func (b *Reader) Peek(n int) ([]byte, os.Error) {
+       if n < 0 {
+               return nil, ErrNegativeCount
+       }
+       if n > len(b.buf) {
+               return nil, ErrBufferFull
+       }
+       for b.w-b.r < n && b.err == nil {
+               b.fill()
+       }
+       m := b.w - b.r
+       if m > n {
+               m = n
+       }
+       err := b.err
+       if m < n && err == nil {
+               err = ErrBufferFull
+       }
+       return b.buf[b.r : b.r+m], err
+}
+
 // Read reads data into p.
 // It returns the number of bytes read into p.
 // If nn < len(p), also returns an error explaining
@@ -129,7 +153,7 @@ func (b *Reader) Read(p []byte) (nn int, err os.Error) {
                if n > b.w-b.r {
                        n = b.w - b.r
                }
-               copy(p[0:n], b.buf[b.r:b.r+n])
+               copy(p[0:n], b.buf[b.r:])
                p = p[n:]
                b.r += n
                b.lastbyte = int(b.buf[b.r-1])
@@ -291,10 +315,10 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) {
        buf := make([]byte, n)
        n = 0
        for i := 0; i < nfull; i++ {
-               copy(buf[n:n+len(full[i])], full[i])
+               copy(buf[n:], full[i])
                n += len(full[i])
        }
-       copy(buf[n:n+len(frag)], frag)
+       copy(buf[n:], frag)
        return buf, err
 }
 
index 2279fe3b12ea20560d30e5e87f4c63d6850cc5e6..876270fcaa32780acd030859af1879003105af77 100644 (file)
@@ -419,3 +419,41 @@ func TestBufferFull(t *testing.T) {
                t.Errorf("second ReadSlice(,) = %q, %v", line, err)
        }
 }
+
+func TestPeek(t *testing.T) {
+       p := make([]byte, 10)
+       buf, _ := NewReaderSize(strings.NewReader("abcdefghij"), 4)
+       if s, err := buf.Peek(1); string(s) != "a" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "a", string(s), err)
+       }
+       if s, err := buf.Peek(4); string(s) != "abcd" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "abcd", string(s), err)
+       }
+       if _, err := buf.Peek(5); err != ErrBufferFull {
+               t.Fatalf("want ErrBufFull got %v", err)
+       }
+       if _, err := buf.Read(p[0:3]); string(p[0:3]) != "abc" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "abc", string(p[0:3]), err)
+       }
+       if s, err := buf.Peek(1); string(s) != "d" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "d", string(s), err)
+       }
+       if s, err := buf.Peek(2); string(s) != "de" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "de", string(s), err)
+       }
+       if _, err := buf.Read(p[0:3]); string(p[0:3]) != "def" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "def", string(p[0:3]), err)
+       }
+       if s, err := buf.Peek(4); string(s) != "ghij" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "ghij", string(s), err)
+       }
+       if _, err := buf.Read(p[0:4]); string(p[0:4]) != "ghij" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "ghij", string(p[0:3]), err)
+       }
+       if s, err := buf.Peek(0); string(s) != "" || err != nil {
+               t.Fatalf("want %q got %q, err=%v", "", string(s), err)
+       }
+       if _, err := buf.Peek(1); err != os.EOF {
+               t.Fatalf("want EOF got %v", err)
+       }
+}