aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/bufio
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2022-02-11 14:53:56 -0800
committerIan Lance Taylor <iant@golang.org>2022-02-11 15:01:19 -0800
commit8dc2499aa62f768c6395c9754b8cabc1ce25c494 (patch)
tree43d7fd2bbfd7ad8c9625a718a5e8718889351994 /libgo/go/bufio
parent9a56779dbc4e2d9c15be8d31e36f2f59be7331a8 (diff)
downloadgcc-8dc2499aa62f768c6395c9754b8cabc1ce25c494.zip
gcc-8dc2499aa62f768c6395c9754b8cabc1ce25c494.tar.gz
gcc-8dc2499aa62f768c6395c9754b8cabc1ce25c494.tar.bz2
libgo: update to Go1.18beta2
gotools/ * Makefile.am (go_cmd_cgo_files): Add ast_go118.go (check-go-tool): Copy golang.org/x/tools directories. * Makefile.in: Regenerate. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/384695
Diffstat (limited to 'libgo/go/bufio')
-rw-r--r--libgo/go/bufio/bufio.go52
-rw-r--r--libgo/go/bufio/bufio_test.go142
-rw-r--r--libgo/go/bufio/example_test.go12
3 files changed, 193 insertions, 13 deletions
diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go
index ec928e7..7483946 100644
--- a/libgo/go/bufio/bufio.go
+++ b/libgo/go/bufio/bufio.go
@@ -68,7 +68,12 @@ func (b *Reader) Size() int { return len(b.buf) }
// Reset discards any buffered data, resets all state, and switches
// the buffered reader to read from r.
+// Calling Reset on the zero value of Reader initializes the internal buffer
+// to the default size.
func (b *Reader) Reset(r io.Reader) {
+ if b.buf == nil {
+ b.buf = make([]byte, defaultBufSize)
+ }
b.reset(b.buf, r)
}
@@ -168,6 +173,10 @@ func (b *Reader) Discard(n int) (discarded int, err error) {
if n == 0 {
return
}
+
+ b.lastByte = -1
+ b.lastRuneSize = -1
+
remain := n
for {
skip := b.Buffered()
@@ -235,6 +244,8 @@ func (b *Reader) Read(p []byte) (n int, err error) {
}
// copy as much as we can
+ // Note: if the slice panics here, it is probably because
+ // the underlying reader returned a bad count. See issue 49795.
n = copy(p, b.buf[b.r:b.w])
b.r += n
b.lastByte = int(b.buf[b.r-1])
@@ -261,8 +272,8 @@ func (b *Reader) ReadByte() (byte, error) {
// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
//
// UnreadByte returns an error if the most recent method called on the
-// Reader was not a read operation. Notably, Peek is not considered a
-// read operation.
+// Reader was not a read operation. Notably, Peek, Discard, and WriteTo are not
+// considered read operations.
func (b *Reader) UnreadByte() error {
if b.lastByte < 0 || b.r == 0 && b.w > 0 {
return ErrInvalidUnreadByte
@@ -497,6 +508,9 @@ func (b *Reader) ReadString(delim byte) (string, error) {
// If the underlying reader supports the WriteTo method,
// this calls the underlying WriteTo without buffering.
func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
+ b.lastByte = -1
+ b.lastRuneSize = -1
+
n, err = b.writeBuf(w)
if err != nil {
return
@@ -581,6 +595,8 @@ func NewWriterSize(w io.Writer, size int) *Writer {
}
// NewWriter returns a new Writer whose buffer has the default size.
+// If the argument io.Writer is already a Writer with large enough buffer size,
+// it returns the underlying Writer.
func NewWriter(w io.Writer) *Writer {
return NewWriterSize(w, defaultBufSize)
}
@@ -590,7 +606,12 @@ func (b *Writer) Size() int { return len(b.buf) }
// Reset discards any unflushed buffered data, clears any error, and
// resets b to write its output to w.
+// Calling Reset on the zero value of Writer initializes the internal buffer
+// to the default size.
func (b *Writer) Reset(w io.Writer) {
+ if b.buf == nil {
+ b.buf = make([]byte, defaultBufSize)
+ }
b.err = nil
b.n = 0
b.wr = w
@@ -623,6 +644,14 @@ func (b *Writer) Flush() error {
// Available returns how many bytes are unused in the buffer.
func (b *Writer) Available() int { return len(b.buf) - b.n }
+// AvailableBuffer returns an empty buffer with b.Available() capacity.
+// This buffer is intended to be appended to and
+// passed to an immediately succeeding Write call.
+// The buffer is only valid until the next write operation on b.
+func (b *Writer) AvailableBuffer() []byte {
+ return b.buf[b.n:][:0]
+}
+
// Buffered returns the number of bytes that have been written into the current buffer.
func (b *Writer) Buffered() int { return b.n }
@@ -720,19 +749,14 @@ func (b *Writer) WriteString(s string) (int, error) {
}
// ReadFrom implements io.ReaderFrom. If the underlying writer
-// supports the ReadFrom method, and b has no buffered data yet,
-// this calls the underlying ReadFrom without buffering.
+// supports the ReadFrom method, this calls the underlying ReadFrom.
+// If there is buffered data and an underlying ReadFrom, this fills
+// the buffer and writes it before calling ReadFrom.
func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
if b.err != nil {
return 0, b.err
}
- if b.Buffered() == 0 {
- if w, ok := b.wr.(io.ReaderFrom); ok {
- n, err = w.ReadFrom(r)
- b.err = err
- return n, err
- }
- }
+ readerFrom, readerFromOK := b.wr.(io.ReaderFrom)
var m int
for {
if b.Available() == 0 {
@@ -740,6 +764,12 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
return n, err1
}
}
+ if readerFromOK && b.Buffered() == 0 {
+ nn, err := readerFrom.ReadFrom(r)
+ b.err = err
+ n += nn
+ return n, err
+ }
nr := 0
for nr < maxConsecutiveEmptyReads {
m, err = r.Read(b.buf[b.n:])
diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go
index ebcc711..ff3396e 100644
--- a/libgo/go/bufio/bufio_test.go
+++ b/libgo/go/bufio/bufio_test.go
@@ -10,6 +10,8 @@ import (
"errors"
"fmt"
"io"
+ "math/rand"
+ "strconv"
"strings"
"testing"
"testing/iotest"
@@ -302,6 +304,40 @@ func TestNoUnreadByteAfterPeek(t *testing.T) {
}
}
+func TestNoUnreadRuneAfterDiscard(t *testing.T) {
+ br := NewReader(strings.NewReader("example"))
+ br.ReadRune()
+ br.Discard(1)
+ if err := br.UnreadRune(); err == nil {
+ t.Error("UnreadRune didn't fail after Discard")
+ }
+}
+
+func TestNoUnreadByteAfterDiscard(t *testing.T) {
+ br := NewReader(strings.NewReader("example"))
+ br.ReadByte()
+ br.Discard(1)
+ if err := br.UnreadByte(); err == nil {
+ t.Error("UnreadByte didn't fail after Discard")
+ }
+}
+
+func TestNoUnreadRuneAfterWriteTo(t *testing.T) {
+ br := NewReader(strings.NewReader("example"))
+ br.WriteTo(io.Discard)
+ if err := br.UnreadRune(); err == nil {
+ t.Error("UnreadRune didn't fail after WriteTo")
+ }
+}
+
+func TestNoUnreadByteAfterWriteTo(t *testing.T) {
+ br := NewReader(strings.NewReader("example"))
+ br.WriteTo(io.Discard)
+ if err := br.UnreadByte(); err == nil {
+ t.Error("UnreadByte didn't fail after WriteTo")
+ }
+}
+
func TestUnreadByte(t *testing.T) {
segments := []string{"Hello, ", "world"}
r := NewReader(&StringReader{data: segments})
@@ -608,6 +644,37 @@ func TestWriter(t *testing.T) {
}
}
+func TestWriterAppend(t *testing.T) {
+ got := new(bytes.Buffer)
+ var want []byte
+ rn := rand.New(rand.NewSource(0))
+ w := NewWriterSize(got, 64)
+ for i := 0; i < 100; i++ {
+ // Obtain a buffer to append to.
+ b := w.AvailableBuffer()
+ if w.Available() != cap(b) {
+ t.Fatalf("Available() = %v, want %v", w.Available(), cap(b))
+ }
+
+ // While not recommended, it is valid to append to a shifted buffer.
+ // This forces Write to copy the input.
+ if rn.Intn(8) == 0 && cap(b) > 0 {
+ b = b[1:1:cap(b)]
+ }
+
+ // Append a random integer of varying width.
+ n := int64(rn.Intn(1 << rn.Intn(30)))
+ want = append(strconv.AppendInt(want, n, 10), ' ')
+ b = append(strconv.AppendInt(b, n, 10), ' ')
+ w.Write(b)
+ }
+ w.Flush()
+
+ if !bytes.Equal(got.Bytes(), want) {
+ t.Errorf("output mismatch:\ngot %s\nwant %s", got.Bytes(), want)
+ }
+}
+
// Check that write errors are returned properly.
type errorWriterTest struct {
@@ -1284,6 +1351,54 @@ func TestWriterReadFromErrNoProgress(t *testing.T) {
}
}
+type readFromWriter struct {
+ buf []byte
+ writeBytes int
+ readFromBytes int
+}
+
+func (w *readFromWriter) Write(p []byte) (int, error) {
+ w.buf = append(w.buf, p...)
+ w.writeBytes += len(p)
+ return len(p), nil
+}
+
+func (w *readFromWriter) ReadFrom(r io.Reader) (int64, error) {
+ b, err := io.ReadAll(r)
+ w.buf = append(w.buf, b...)
+ w.readFromBytes += len(b)
+ return int64(len(b)), err
+}
+
+// Test that calling (*Writer).ReadFrom with a partially-filled buffer
+// fills the buffer before switching over to ReadFrom.
+func TestWriterReadFromWithBufferedData(t *testing.T) {
+ const bufsize = 16
+
+ input := createTestInput(64)
+ rfw := &readFromWriter{}
+ w := NewWriterSize(rfw, bufsize)
+
+ const writeSize = 8
+ if n, err := w.Write(input[:writeSize]); n != writeSize || err != nil {
+ t.Errorf("w.Write(%v bytes) = %v, %v; want %v, nil", writeSize, n, err, writeSize)
+ }
+ n, err := w.ReadFrom(bytes.NewReader(input[writeSize:]))
+ if wantn := len(input[writeSize:]); int(n) != wantn || err != nil {
+ t.Errorf("io.Copy(w, %v bytes) = %v, %v; want %v, nil", wantn, n, err, wantn)
+ }
+ if err := w.Flush(); err != nil {
+ t.Errorf("w.Flush() = %v, want nil", err)
+ }
+
+ if got, want := rfw.writeBytes, bufsize; got != want {
+ t.Errorf("wrote %v bytes with Write, want %v", got, want)
+ }
+ if got, want := rfw.readFromBytes, len(input)-bufsize; got != want {
+ t.Errorf("wrote %v bytes with ReadFrom, want %v", got, want)
+ }
+}
+
func TestReadZero(t *testing.T) {
for _, size := range []int{100, 2} {
t.Run(fmt.Sprintf("bufsize=%d", size), func(t *testing.T) {
@@ -1312,6 +1427,7 @@ func TestReaderReset(t *testing.T) {
if string(buf) != "foo" {
t.Errorf("buf = %q; want foo", buf)
}
+
r.Reset(strings.NewReader("bar bar"))
all, err := io.ReadAll(r)
if err != nil {
@@ -1320,12 +1436,23 @@ func TestReaderReset(t *testing.T) {
if string(all) != "bar bar" {
t.Errorf("ReadAll = %q; want bar bar", all)
}
+
+ *r = Reader{} // zero out the Reader
+ r.Reset(strings.NewReader("bar bar"))
+ all, err = io.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
+ var buf1, buf2, buf3 bytes.Buffer
w := NewWriter(&buf1)
w.WriteString("foo")
+
w.Reset(&buf2) // and not flushed
w.WriteString("bar")
w.Flush()
@@ -1335,6 +1462,17 @@ func TestWriterReset(t *testing.T) {
if buf2.String() != "bar" {
t.Errorf("buf2 = %q; want bar", buf2.String())
}
+
+ *w = Writer{} // zero out the Writer
+ w.Reset(&buf3) // and not flushed
+ w.WriteString("bar")
+ w.Flush()
+ if buf1.String() != "" {
+ t.Errorf("buf1 = %q; want empty", buf1.String())
+ }
+ if buf3.String() != "bar" {
+ t.Errorf("buf3 = %q; want bar", buf3.String())
+ }
}
func TestReaderDiscard(t *testing.T) {
@@ -1382,7 +1520,7 @@ func TestReaderDiscard(t *testing.T) {
wantBuffered: 0,
},
// Any error from filling shouldn't show up until we
- // get past the valid bytes. Here we return we return 5 valid bytes at the same time
+ // get past the valid bytes. Here we return 5 valid bytes at the same time
// as an error, but test that we don't see the error from Discard.
{
name: "fill error, discard less",
diff --git a/libgo/go/bufio/example_test.go b/libgo/go/bufio/example_test.go
index 8885d40..a864d11 100644
--- a/libgo/go/bufio/example_test.go
+++ b/libgo/go/bufio/example_test.go
@@ -20,6 +20,18 @@ func ExampleWriter() {
// Output: Hello, world!
}
+func ExampleWriter_AvailableBuffer() {
+ w := bufio.NewWriter(os.Stdout)
+ for _, i := range []int64{1, 2, 3, 4} {
+ b := w.AvailableBuffer()
+ b = strconv.AppendInt(b, i, 10)
+ b = append(b, ' ')
+ w.Write(b)
+ }
+ w.Flush()
+ // Output: 1 2 3 4
+}
+
// The simplest use of a Scanner, to read standard input as a set of lines.
func ExampleScanner_lines() {
scanner := bufio.NewScanner(os.Stdin)