summaryrefslogtreecommitdiff
path: root/src/pkg/bytes/buffer.go
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2009-12-06 12:03:52 -0800
committerRob Pike <r@golang.org>2009-12-06 12:03:52 -0800
commit25ce0349b3305d038c757b2a49c91c7ca05848c9 (patch)
tree9ca97cb7ed859f7cc96604a32683841585024c79 /src/pkg/bytes/buffer.go
parent956d8c7dec13e1a90061f81c321d6ccd588a3a6e (diff)
downloadgolang-25ce0349b3305d038c757b2a49c91c7ca05848c9.tar.gz
Make printing faster by avoiding mallocs and some other advances.
Roughly 33% faster for simple cases, probably more for complex ones. Before: mallocs per Sprintf(""): 4 mallocs per Sprintf("xxx"): 6 mallocs per Sprintf("%x"): 10 mallocs per Sprintf("%x %x"): 12 Now: mallocs per Sprintf(""): 2 mallocs per Sprintf("xxx"): 3 mallocs per Sprintf("%x"): 5 mallocs per Sprintf("%x %x"): 7 Speed improves because of avoiding mallocs and also by sharing a bytes.Buffer between print.go and format.go rather than copying the data back after each printed item. Before: fmt_test.BenchmarkSprintfEmpty 1000000 1346 ns/op fmt_test.BenchmarkSprintfString 500000 3461 ns/op fmt_test.BenchmarkSprintfInt 500000 3671 ns/op Now: fmt_test.BenchmarkSprintfEmpty 2000000 995 ns/op fmt_test.BenchmarkSprintfString 1000000 2745 ns/op fmt_test.BenchmarkSprintfInt 1000000 2391 ns/op fmt_test.BenchmarkSprintfIntInt 500000 3751 ns/op I believe there is more to get but this is a good milestone. R=rsc CC=golang-dev, hong http://codereview.appspot.com/166076
Diffstat (limited to 'src/pkg/bytes/buffer.go')
-rw-r--r--src/pkg/bytes/buffer.go74
1 files changed, 37 insertions, 37 deletions
diff --git a/src/pkg/bytes/buffer.go b/src/pkg/bytes/buffer.go
index 09202506f..61780947f 100644
--- a/src/pkg/bytes/buffer.go
+++ b/src/pkg/bytes/buffer.go
@@ -32,9 +32,10 @@ func copyBytes(dst []byte, doff int, src []byte) {
// with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {
- buf []byte; // contents are the bytes buf[off : len(buf)]
- off int; // read at &buf[off], write at &buf[len(buf)]
- oneByte [1]byte; // avoid allocation of slice on each WriteByte
+ buf []byte; // contents are the bytes buf[off : len(buf)]
+ off int; // read at &buf[off], write at &buf[len(buf)]
+ oneByte [1]byte; // avoid allocation of slice on each WriteByte
+ bootstrap [64]byte; // memory to hold first slice; helps small buffers (Printf) avoid allocation.
}
// Bytes returns the contents of the unread portion of the buffer;
@@ -69,29 +70,51 @@ func (b *Buffer) Truncate(n int) {
// b.Reset() is the same as b.Truncate(0).
func (b *Buffer) Reset() { b.Truncate(0) }
+// Resize buffer to guarantee enough space for n more bytes.
+// After this call, the state of b.buf is inconsistent.
+// It must be fixed up as is done in Write and WriteString.
+func (b *Buffer) resize(n int) {
+ var buf []byte;
+ if b.buf == nil && n <= len(b.bootstrap) {
+ buf = &b.bootstrap
+ } else {
+ buf = b.buf;
+ if len(b.buf)+n > cap(b.buf) {
+ // not enough space anywhere
+ buf = make([]byte, 2*cap(b.buf)+n)
+ }
+ copy(buf, b.buf[b.off:]);
+ }
+ b.buf = buf;
+ b.off = 0;
+}
+
// Write appends the contents of p to the buffer. The return
// value n is the length of p; err is always nil.
func (b *Buffer) Write(p []byte) (n int, err os.Error) {
m := b.Len();
n = len(p);
-
if len(b.buf)+n > cap(b.buf) {
- // not enough space at end
- buf := b.buf;
- if m+n > cap(b.buf) {
- // not enough space anywhere
- buf = make([]byte, 2*cap(b.buf)+n)
- }
- copyBytes(buf, 0, b.buf[b.off:b.off+m]);
- b.buf = buf;
- b.off = 0;
+ b.resize(n)
}
-
b.buf = b.buf[0 : b.off+m+n];
copyBytes(b.buf, b.off+m, p);
return n, nil;
}
+// 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) {
+ m := b.Len();
+ n = len(s);
+ if len(b.buf)+n > cap(b.buf) {
+ b.resize(n)
+ }
+ b.buf = b.buf[0 : b.off+m+n];
+ copyString(b.buf, b.off+m, s);
+ 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
@@ -146,29 +169,6 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
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) {
- m := b.Len();
- n = len(s);
-
- if len(b.buf)+n > cap(b.buf) {
- // not enough space at end
- buf := b.buf;
- if m+n > cap(b.buf) {
- // not enough space anywhere
- buf = make([]byte, 2*cap(b.buf)+n)
- }
- copyBytes(buf, 0, b.buf[b.off:b.off+m]);
- b.buf = buf;
- b.off = 0;
- }
-
- b.buf = b.buf[0 : b.off+m+n];
- copyString(b.buf, b.off+m, s);
- return n, nil;
-}
-
// WriteByte appends the byte c to the buffer.
// The returned error is always nil, but is included
// to match bufio.Writer's WriteByte.