1
0
mirror of https://github.com/golang/go synced 2024-11-26 22:31:23 -07:00

bufio: add Writer.AvailableBuffer

This adds a new Writer.AvailableBuffer method that returns
an empty buffer with a possibly non-empty capacity for use
with append-like APIs.

The typical usage pattern is something like:
	b := bw.AvailableBuffer()
	b = appendValue(b, v)
	bw.Write(b)

It allows logic combining append-like APIs with bufio.Writer to avoid
needing to allocate and manage buffers themselves and allows the
append-like APIs to directly write into the buffer for a bufio.Writer.

Fixes #47527

Change-Id: I9cd169f3f8e8c7cd40818caf3daf1944c826fc66
Reviewed-on: https://go-review.googlesource.com/c/go/+/345569
Trust: Joe Tsai <joetsai@digital-static.net>
Run-TryBot: Joe Tsai <joetsai@digital-static.net>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Joe Tsai 2021-08-04 01:22:45 -07:00
parent 23832ba2e2
commit 0d8a4bfc96
3 changed files with 53 additions and 0 deletions

View File

@ -633,6 +633,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 }

View File

@ -10,6 +10,8 @@ import (
"errors"
"fmt"
"io"
"math/rand"
"strconv"
"strings"
"testing"
"testing/iotest"
@ -608,6 +610,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 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 {

View File

@ -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)