diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2013-11-06 19:49:01 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2013-11-06 19:49:01 +0000 |
commit | f038dae646bac2b31be98ab592c0e5206d2d96f5 (patch) | |
tree | 39530b071991b2326f881b2a30a2d82d6c133fd6 /libgo/go/bufio | |
parent | f20f261304993444741e0f0a14d3147e591bc660 (diff) | |
download | gcc-f038dae646bac2b31be98ab592c0e5206d2d96f5.zip gcc-f038dae646bac2b31be98ab592c0e5206d2d96f5.tar.gz gcc-f038dae646bac2b31be98ab592c0e5206d2d96f5.tar.bz2 |
libgo: Update to October 24 version of master library.
From-SVN: r204466
Diffstat (limited to 'libgo/go/bufio')
-rw-r--r-- | libgo/go/bufio/bufio.go | 86 | ||||
-rw-r--r-- | libgo/go/bufio/bufio_test.go | 97 | ||||
-rw-r--r-- | libgo/go/bufio/example_test.go | 8 | ||||
-rw-r--r-- | libgo/go/bufio/scan.go | 6 |
4 files changed, 168 insertions, 29 deletions
diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go index df3501f..d1ff3c9 100644 --- a/libgo/go/bufio/bufio.go +++ b/libgo/go/bufio/bufio.go @@ -51,12 +51,9 @@ func NewReaderSize(rd io.Reader, size int) *Reader { if size < minReadBufferSize { size = minReadBufferSize } - return &Reader{ - buf: make([]byte, size), - rd: rd, - lastByte: -1, - lastRuneSize: -1, - } + r := new(Reader) + r.reset(make([]byte, size), rd) + return r } // NewReader returns a new Reader whose buffer has the default size. @@ -64,6 +61,21 @@ func NewReader(rd io.Reader) *Reader { return NewReaderSize(rd, defaultBufSize) } +// Reset discards any buffered data, resets all state, and switches +// the buffered reader to read from r. +func (b *Reader) Reset(r io.Reader) { + b.reset(b.buf, r) +} + +func (b *Reader) reset(buf []byte, r io.Reader) { + *b = Reader{ + buf: buf, + rd: r, + lastByte: -1, + lastRuneSize: -1, + } +} + var errNegativeRead = errors.New("bufio: reader returned negative count from Read") // fill reads a new chunk into the buffer. @@ -234,7 +246,7 @@ func (b *Reader) Buffered() int { return b.w - b.r } // ReadSlice reads until the first occurrence of delim in the input, // returning a slice pointing at the bytes in the buffer. -// The bytes stop being valid at the next read call. +// The bytes stop being valid at the next read. // If ReadSlice encounters an error before finding a delimiter, // it returns all the data in the buffer and the error itself (often io.EOF). // ReadSlice fails with error ErrBufferFull if the buffer fills without a delim. @@ -381,7 +393,8 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err error) { // For simple uses, a Scanner may be more convenient. func (b *Reader) ReadString(delim byte) (line string, err error) { bytes, err := b.ReadBytes(delim) - return string(bytes), err + line = string(bytes) + return line, err } // WriteTo implements io.WriterTo. @@ -424,6 +437,9 @@ func (b *Reader) writeBuf(w io.Writer) (int64, error) { // Writer implements buffering for an io.Writer object. // If an error occurs writing to a Writer, no more data will be // accepted and all subsequent writes will return the error. +// After all data has been written, the client should call the +// Flush method to guarantee all data has been forwarded to +// the underlying io.Writer. type Writer struct { err error buf []byte @@ -434,28 +450,41 @@ type Writer struct { // NewWriterSize returns a new Writer whose buffer has at least the specified // size. If the argument io.Writer is already a Writer with large enough // size, it returns the underlying Writer. -func NewWriterSize(wr io.Writer, size int) *Writer { +func NewWriterSize(w io.Writer, size int) *Writer { // Is it already a Writer? - b, ok := wr.(*Writer) + b, ok := w.(*Writer) if ok && len(b.buf) >= size { return b } if size <= 0 { size = defaultBufSize } - b = new(Writer) - b.buf = make([]byte, size) - b.wr = wr - return b + return &Writer{ + buf: make([]byte, size), + wr: w, + } } // NewWriter returns a new Writer whose buffer has the default size. -func NewWriter(wr io.Writer) *Writer { - return NewWriterSize(wr, defaultBufSize) +func NewWriter(w io.Writer) *Writer { + return NewWriterSize(w, defaultBufSize) +} + +// Reset discards any unflushed buffered data, clears any error, and +// resets b to write its output to w. +func (b *Writer) Reset(w io.Writer) { + b.err = nil + b.n = 0 + b.wr = w } // Flush writes any buffered data to the underlying io.Writer. func (b *Writer) Flush() error { + err := b.flush() + return err +} + +func (b *Writer) flush() error { if b.err != nil { return b.err } @@ -498,7 +527,7 @@ func (b *Writer) Write(p []byte) (nn int, err error) { } else { n = copy(b.buf[b.n:], p) b.n += n - b.Flush() + b.flush() } nn += n p = p[n:] @@ -517,7 +546,7 @@ func (b *Writer) WriteByte(c byte) error { if b.err != nil { return b.err } - if b.Available() <= 0 && b.Flush() != nil { + if b.Available() <= 0 && b.flush() != nil { return b.err } b.buf[b.n] = c @@ -540,7 +569,7 @@ func (b *Writer) WriteRune(r rune) (size int, err error) { } n := b.Available() if n < utf8.UTFMax { - if b.Flush(); b.err != nil { + if b.flush(); b.err != nil { return 0, b.err } n = b.Available() @@ -565,7 +594,7 @@ func (b *Writer) WriteString(s string) (int, error) { b.n += n nn += n s = s[n:] - b.Flush() + b.flush() } if b.err != nil { return nn, b.err @@ -585,23 +614,28 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) { } var m int for { + if b.Available() == 0 { + if err1 := b.flush(); err1 != nil { + return n, err1 + } + } m, err = r.Read(b.buf[b.n:]) if m == 0 { break } b.n += m n += int64(m) - if b.Available() == 0 { - if err1 := b.Flush(); err1 != nil { - return n, err1 - } - } if err != nil { break } } if err == io.EOF { - err = nil + // If we filled the buffer exactly, flush pre-emptively. + if b.Available() == 0 { + err = b.flush() + } else { + err = nil + } } return n, err } diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go index 79ed0f1..41bd3d45 100644 --- a/libgo/go/bufio/bufio_test.go +++ b/libgo/go/bufio/bufio_test.go @@ -847,6 +847,10 @@ func TestWriterReadFrom(t *testing.T) { t.Errorf("ws[%d],rs[%d]: w.ReadFrom(r) = %d, %v, want %d, nil", wi, ri, n, err, len(input)) continue } + if err := w.Flush(); err != nil { + t.Errorf("Flush returned %v", err) + continue + } if got, want := b.String(), string(input); got != want { t.Errorf("ws[%d], rs[%d]:\ngot %q\nwant %q\n", wi, ri, got, want) } @@ -1003,6 +1007,56 @@ func TestReaderClearError(t *testing.T) { } } +// Test for golang.org/issue/5947 +func TestWriterReadFromWhileFull(t *testing.T) { + buf := new(bytes.Buffer) + w := NewWriterSize(buf, 10) + + // Fill buffer exactly. + n, err := w.Write([]byte("0123456789")) + if n != 10 || err != nil { + t.Fatalf("Write returned (%v, %v), want (10, nil)", n, err) + } + + // Use ReadFrom to read in some data. + n2, err := w.ReadFrom(strings.NewReader("abcdef")) + if n2 != 6 || err != nil { + t.Fatalf("ReadFrom returned (%v, %v), want (6, nil)", n, err) + } +} + +func TestReaderReset(t *testing.T) { + r := NewReader(strings.NewReader("foo foo")) + buf := make([]byte, 3) + r.Read(buf) + if string(buf) != "foo" { + t.Errorf("buf = %q; want foo", buf) + } + r.Reset(strings.NewReader("bar bar")) + all, err := ioutil.ReadAll(r) + if err != nil { + t.Fatal(err) + } + if string(all) != "bar bar" { + t.Errorf("ReadAll = %q; want bar bar", all) + } +} + +func TestWriterReset(t *testing.T) { + var buf1, buf2 bytes.Buffer + w := NewWriter(&buf1) + w.WriteString("foo") + w.Reset(&buf2) // and not flushed + w.WriteString("bar") + w.Flush() + if buf1.String() != "" { + t.Errorf("buf1 = %q; want empty", buf1.String()) + } + if buf2.String() != "bar" { + t.Errorf("buf2 = %q; want bar", buf2.String()) + } +} + // An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have. type onlyReader struct { r io.Reader @@ -1083,3 +1137,46 @@ func BenchmarkWriterCopyNoReadFrom(b *testing.B) { io.Copy(dst, src) } } + +func BenchmarkReaderEmpty(b *testing.B) { + b.ReportAllocs() + str := strings.Repeat("x", 16<<10) + for i := 0; i < b.N; i++ { + br := NewReader(strings.NewReader(str)) + n, err := io.Copy(ioutil.Discard, br) + if err != nil { + b.Fatal(err) + } + if n != int64(len(str)) { + b.Fatal("wrong length") + } + } +} + +func BenchmarkWriterEmpty(b *testing.B) { + b.ReportAllocs() + str := strings.Repeat("x", 1<<10) + bs := []byte(str) + for i := 0; i < b.N; i++ { + bw := NewWriter(ioutil.Discard) + bw.Flush() + bw.WriteByte('a') + bw.Flush() + bw.WriteRune('B') + bw.Flush() + bw.Write(bs) + bw.Flush() + bw.WriteString(str) + bw.Flush() + } +} + +func BenchmarkWriterFlush(b *testing.B) { + b.ReportAllocs() + bw := NewWriter(ioutil.Discard) + str := strings.Repeat("x", 50) + for i := 0; i < b.N; i++ { + bw.WriteString(str) + bw.Flush() + } +} diff --git a/libgo/go/bufio/example_test.go b/libgo/go/bufio/example_test.go index 08a3944..3da9141 100644 --- a/libgo/go/bufio/example_test.go +++ b/libgo/go/bufio/example_test.go @@ -12,6 +12,14 @@ import ( "strings" ) +func ExampleWriter() { + w := bufio.NewWriter(os.Stdout) + fmt.Fprint(w, "Hello, ") + fmt.Fprint(w, "world!") + w.Flush() // Don't forget to flush! + // Output: Hello, world! +} + // The simplest use of a Scanner, to read standard input as a set of lines. func ExampleScanner_lines() { scanner := bufio.NewScanner(os.Stdin) diff --git a/libgo/go/bufio/scan.go b/libgo/go/bufio/scan.go index 2e1a2e9..423505f 100644 --- a/libgo/go/bufio/scan.go +++ b/libgo/go/bufio/scan.go @@ -44,8 +44,8 @@ type Scanner struct { // to give. The return values are the number of bytes to advance the input // and the next token to return to the user, plus an error, if any. If the // data does not yet hold a complete token, for instance if it has no newline -// while scanning lines, SplitFunc can return (0, nil) to signal the Scanner -// to read more data into the slice and try again with a longer slice +// while scanning lines, SplitFunc can return (0, nil, nil) to signal the +// Scanner to read more data into the slice and try again with a longer slice // starting at the same point in the input. // // If the returned error is non-nil, scanning stops and the error @@ -287,7 +287,7 @@ func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { return 0, nil, nil } -// isSpace returns whether the character is a Unicode white space character. +// isSpace reports whether the character is a Unicode white space character. // We avoid dependency on the unicode package, but check validity of the implementation // in the tests. func isSpace(r rune) bool { |