Skip to content

Commit 25fe91a

Browse files
committed
[tailscale1.17] 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 golang#47527 Change-Id: I9cd169f3f8e8c7cd40818caf3daf1944c826fc66 Reviewed-on: https://go-review.googlesource.com/c/go/+/345569 Trust: Joe Tsai <[email protected]> Run-TryBot: Joe Tsai <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> (cherry picked from golang.org/cl/345569)
1 parent 02953ff commit 25fe91a

File tree

4 files changed

+55
-0
lines changed

4 files changed

+55
-0
lines changed

api/go1.tailscale.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
pkg bufio, method (*Writer) AvailableBuffer() []uint8
2+
pkg bufio, method (ReadWriter) AvailableBuffer() []uint8
13
pkg crypto/elliptic, func BigInt2BytesLe([]uint8, *big.Int)
24
pkg crypto/elliptic, func BigInt2Uint64Le([]uint64, *big.Int)
35
pkg crypto/elliptic, func BytesLe2BigInt([]uint8) *big.Int

src/bufio/bufio.go

+8
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,14 @@ func (b *Writer) Flush() error {
623623
// Available returns how many bytes are unused in the buffer.
624624
func (b *Writer) Available() int { return len(b.buf) - b.n }
625625

626+
// AvailableBuffer returns an empty buffer with b.Available() capacity.
627+
// This buffer is intended to be appended to and
628+
// passed to an immediately succeeding Write call.
629+
// The buffer is only valid until the next write operation on b.
630+
func (b *Writer) AvailableBuffer() []byte {
631+
return b.buf[b.n:][:0]
632+
}
633+
626634
// Buffered returns the number of bytes that have been written into the current buffer.
627635
func (b *Writer) Buffered() int { return b.n }
628636

src/bufio/bufio_test.go

+33
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"errors"
1111
"fmt"
1212
"io"
13+
"math/rand"
14+
"strconv"
1315
"strings"
1416
"testing"
1517
"testing/iotest"
@@ -608,6 +610,37 @@ func TestWriter(t *testing.T) {
608610
}
609611
}
610612

613+
func TestWriterAppend(t *testing.T) {
614+
got := new(bytes.Buffer)
615+
var want []byte
616+
rn := rand.New(rand.NewSource(0))
617+
w := NewWriterSize(got, 64)
618+
for i := 0; i < 100; i++ {
619+
// Obtain a buffer to append to.
620+
b := w.AvailableBuffer()
621+
if w.Available() != cap(b) {
622+
t.Fatalf("Available() = %v, want %v", w.Available(), cap(b))
623+
}
624+
625+
// While not recommended, it is valid to append to a shifted buffer.
626+
// This forces Write to copy the the input.
627+
if rn.Intn(8) == 0 && cap(b) > 0 {
628+
b = b[1:1:cap(b)]
629+
}
630+
631+
// Append a random integer of varying width.
632+
n := int64(rn.Intn(1 << rn.Intn(30)))
633+
want = append(strconv.AppendInt(want, n, 10), ' ')
634+
b = append(strconv.AppendInt(b, n, 10), ' ')
635+
w.Write(b)
636+
}
637+
w.Flush()
638+
639+
if !bytes.Equal(got.Bytes(), want) {
640+
t.Errorf("output mismatch:\ngot %s\nwant %s", got.Bytes(), want)
641+
}
642+
}
643+
611644
// Check that write errors are returned properly.
612645

613646
type errorWriterTest struct {

src/bufio/example_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ func ExampleWriter() {
2020
// Output: Hello, world!
2121
}
2222

23+
func ExampleWriter_AvailableBuffer() {
24+
w := bufio.NewWriter(os.Stdout)
25+
for _, i := range []int64{1, 2, 3, 4} {
26+
b := w.AvailableBuffer()
27+
b = strconv.AppendInt(b, i, 10)
28+
b = append(b, ' ')
29+
w.Write(b)
30+
}
31+
w.Flush()
32+
// Output: 1 2 3 4
33+
}
34+
2335
// The simplest use of a Scanner, to read standard input as a set of lines.
2436
func ExampleScanner_lines() {
2537
scanner := bufio.NewScanner(os.Stdin)

0 commit comments

Comments
 (0)