summaryrefslogtreecommitdiff
path: root/src/pkg/bytes/buffer.go
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2009-12-03 12:56:16 -0800
committerRob Pike <r@golang.org>2009-12-03 12:56:16 -0800
commitcc74bcd3184136dd6a578a8b88f6027f1d94891c (patch)
tree0f4e9f9e8d22137c9cb112e5b4333e40c53218e3 /src/pkg/bytes/buffer.go
parentc263db17c6083a4cacb03da16a507ba23a54515f (diff)
downloadgolang-cc74bcd3184136dd6a578a8b88f6027f1d94891c.tar.gz
Add ReadFrom and WriteTo methods to bytes.Buffer, to enable i/o without buffer allocation.
Use them in Copy and Copyn. Speed up ReadFile by using ReadFrom and avoiding Copy altogether (a minor win). R=rsc, gri CC=golang-dev http://codereview.appspot.com/166041
Diffstat (limited to 'src/pkg/bytes/buffer.go')
-rw-r--r--src/pkg/bytes/buffer.go55
1 files changed, 55 insertions, 0 deletions
diff --git a/src/pkg/bytes/buffer.go b/src/pkg/bytes/buffer.go
index ab6f837aa..8fa64524c 100644
--- a/src/pkg/bytes/buffer.go
+++ b/src/pkg/bytes/buffer.go
@@ -7,6 +7,7 @@ package bytes
// Simple byte buffer for marshaling data.
import (
+ "io";
"os";
)
@@ -91,6 +92,60 @@ func (b *Buffer) Write(p []byte) (n int, err os.Error) {
return n, nil;
}
+// MinRead is the minimum slice size passed to a Read call by
+// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond
+// what is required to hold the contents of r, ReadFrom will not grow the
+// underlying buffer.
+const MinRead = 512
+
+// ReadFrom reads data from r until EOF and appends it to the buffer.
+// The return value n is the number of bytes read.
+// Any error except os.EOF encountered during the read
+// is also returned.
+func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) {
+ for {
+ if cap(b.buf)-len(b.buf) < MinRead {
+ var newBuf []byte;
+ // can we get space without allocation?
+ if b.off+cap(b.buf)-len(b.buf) >= MinRead {
+ // reuse beginning of buffer
+ newBuf = b.buf[0 : len(b.buf)-b.off]
+ } else {
+ // not enough space at end; put space on end
+ newBuf = make([]byte, len(b.buf)-b.off, 2*(cap(b.buf)-b.off)+MinRead)
+ }
+ copy(newBuf, b.buf[b.off:]);
+ b.buf = newBuf;
+ b.off = 0;
+ }
+ m, e := r.Read(b.buf[len(b.buf):cap(b.buf)]);
+ b.buf = b.buf[b.off : len(b.buf)+m];
+ n += int64(m);
+ if e == os.EOF {
+ break
+ }
+ if e != nil {
+ return n, e
+ }
+ }
+ return n, nil; // err is EOF, so return nil explicitly
+}
+
+// WriteTo writes data to w until the buffer is drained or an error
+// occurs. The return value n is the number of bytes written.
+// Any error encountered during the write is also returned.
+func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
+ for b.off < len(b.buf) {
+ m, e := w.Write(b.buf[b.off:]);
+ n += int64(m);
+ b.off += m;
+ if e != nil {
+ return n, e
+ }
+ }
+ return;
+}
+
// WriteString appends the contents of s to the buffer. The return
// value n is the length of s; err is always nil.
func (b *Buffer) WriteString(s string) (n int, err os.Error) {