// Reader implements buffering for an io.Reader object.
type Reader struct {
- buf []byte // either nil or []byte of size bufSize
+ buf []byte // either nil or []byte of length bufSize
bufSize int
rd io.Reader
r, w int
}
// Buffer is full?
- if b.Buffered() >= len(b.buf) {
+ if b.Buffered() >= b.bufSize {
b.r = b.w
return b.buf, ErrBufferFull
}
// If an error occurs writing to a Writer, no more data will be
// accepted and all subsequent writes will return the error.
type Writer struct {
- err error
- buf []byte
- n int
- wr io.Writer
+ err error
+ buf []byte // either nil or []byte of length bufSize
+ bufSize int
+ n int
+ wr io.Writer
}
// NewWriterSize returns a new Writer whose buffer has at least the specified
func NewWriterSize(wr io.Writer, size int) *Writer {
// Is it already a Writer?
b, ok := wr.(*Writer)
- if ok && len(b.buf) >= size {
+ if ok && b.bufSize >= size {
return b
}
if size <= 0 {
size = defaultBufSize
}
- b = new(Writer)
- // TODO(bradfitz): make Writer buffers lazy too, like Reader's
- b.buf = make([]byte, size)
- b.wr = wr
+ b = &Writer{
+ wr: wr,
+ bufSize: size,
+ }
+ if size > defaultBufSize {
+ // TODO(bradfitz): make all buffer sizes recycle
+ b.buf = make([]byte, b.bufSize)
+ }
return b
}
return NewWriterSize(wr, defaultBufSize)
}
+// allocBuf makes b.buf non-nil.
+func (b *Writer) allocBuf() {
+ if b.buf != nil {
+ return
+ }
+ select {
+ case b.buf = <-bufCache:
+ b.buf = b.buf[:b.bufSize]
+ default:
+ b.buf = make([]byte, b.bufSize, defaultBufSize)
+ }
+}
+
+// putBuf returns b.buf if it's unused.
+func (b *Writer) putBuf() {
+ if b.n == 0 && cap(b.buf) == defaultBufSize {
+ select {
+ case bufCache <- b.buf:
+ b.buf = nil
+ default:
+ }
+ }
+}
+
// Flush writes any buffered data to the underlying io.Writer.
func (b *Writer) Flush() error {
+ err := b.flush()
+ b.putBuf()
+ return err
+}
+
+func (b *Writer) flush() error {
if b.err != nil {
return b.err
}
}
// Available returns how many bytes are unused in the buffer.
-func (b *Writer) Available() int { return len(b.buf) - b.n }
+func (b *Writer) Available() int { return b.bufSize - b.n }
// Buffered returns the number of bytes that have been written into the current buffer.
func (b *Writer) Buffered() int { return b.n }
// If nn < len(p), it also returns an error explaining
// why the write is short.
func (b *Writer) Write(p []byte) (nn int, err error) {
+ b.allocBuf()
for len(p) > b.Available() && b.err == nil {
var n int
if b.Buffered() == 0 {
} else {
n = copy(b.buf[b.n:], p)
b.n += n
- b.Flush()
+ b.flush()
}
nn += n
p = p[n:]
if b.err != nil {
return b.err
}
- if b.Available() <= 0 && b.Flush() != nil {
+ if b.Available() <= 0 && b.flush() != nil {
return b.err
}
+ if b.buf == nil {
+ b.allocBuf()
+ }
b.buf[b.n] = c
b.n++
return nil
// WriteRune writes a single Unicode code point, returning
// the number of bytes written and any error.
func (b *Writer) WriteRune(r rune) (size int, err error) {
+ if b.buf == nil {
+ b.allocBuf()
+ }
if r < utf8.RuneSelf {
err = b.WriteByte(byte(r))
if err != nil {
}
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()
// If the count is less than len(s), it also returns an error explaining
// why the write is short.
func (b *Writer) WriteString(s string) (int, error) {
+ b.allocBuf()
nn := 0
for len(s) > b.Available() && b.err == nil {
n := copy(b.buf[b.n:], s)
b.n += n
nn += n
s = s[n:]
- b.Flush()
+ b.flush()
}
if b.err != nil {
return nn, b.err
// ReadFrom implements io.ReaderFrom.
func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
+ b.allocBuf()
if b.Buffered() == 0 {
if w, ok := b.wr.(io.ReaderFrom); ok {
return w.ReadFrom(r)
b.n += m
n += int64(m)
if b.Available() == 0 {
- if err1 := b.Flush(); err1 != nil {
+ if err1 := b.flush(); err1 != nil {
return n, err1
}
}