aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/encoding
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@golang.org>2011-05-27 16:29:33 -0700
committerBrad Fitzpatrick <bradfitz@golang.org>2011-05-27 16:29:33 -0700
commitf7a266a5aa73d314e77f4c2aa02c2605568d65b2 (patch)
treef5b25cc66d13f040195d314376d8f7106119e4cb /src/pkg/encoding
parent3b980579b42299c3bd31ffd433824c43a7b13523 (diff)
downloadgo-f7a266a5aa73d314e77f4c2aa02c2605568d65b2.tar.xz
encoding/binary: add a non-reflect fast path for Write
before/after: binary.BenchmarkWrite 100000 18312 ns/op binary.BenchmarkWrite 500000 4468 ns/op R=rsc, gri CC=golang-dev https://golang.org/cl/4515154
Diffstat (limited to 'src/pkg/encoding')
-rw-r--r--src/pkg/encoding/binary/binary.go104
-rw-r--r--src/pkg/encoding/binary/binary_test.go32
2 files changed, 111 insertions, 25 deletions
diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go
index d0185ebb71..8e55cb23b7 100644
--- a/src/pkg/encoding/binary/binary.go
+++ b/src/pkg/encoding/binary/binary.go
@@ -125,37 +125,18 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// Bytes read from r are decoded using the specified byte order
// and written to successive fields of the data.
func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
- // Fast path for basic types
- var n int
- switch data.(type) {
- case *int8:
- n = 1
- case *uint8:
- n = 1
- case *int16:
- n = 2
- case *uint16:
- n = 2
- case *int32:
- n = 4
- case *uint32:
- n = 4
- case *int64:
- n = 8
- case *uint64:
- n = 8
- }
- if n != 0 {
- var buf [8]byte
- bs := buf[:n]
+ // Fast path for basic types.
+ if n := intDestSize(data); n != 0 {
+ var b [8]byte
+ bs := b[:n]
if _, err := io.ReadFull(r, bs); err != nil {
return err
}
switch v := data.(type) {
case *int8:
- *v = int8(buf[0])
+ *v = int8(b[0])
case *uint8:
- *v = buf[0]
+ *v = b[0]
case *int16:
*v = int16(order.Uint16(bs))
case *uint16:
@@ -203,6 +184,63 @@ func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
// Bytes written to w are encoded using the specified byte order
// and read from successive fields of the data.
func Write(w io.Writer, order ByteOrder, data interface{}) os.Error {
+ // Fast path for basic types.
+ var b [8]byte
+ var bs []byte
+ switch v := data.(type) {
+ case *int8:
+ bs = b[:1]
+ b[0] = byte(*v)
+ case int8:
+ bs = b[:1]
+ b[0] = byte(v)
+ case *uint8:
+ bs = b[:1]
+ b[0] = *v
+ case uint8:
+ bs = b[:1]
+ b[0] = byte(v)
+ case *int16:
+ bs = b[:2]
+ order.PutUint16(bs, uint16(*v))
+ case int16:
+ bs = b[:2]
+ order.PutUint16(bs, uint16(v))
+ case *uint16:
+ bs = b[:2]
+ order.PutUint16(bs, *v)
+ case uint16:
+ bs = b[:2]
+ order.PutUint16(bs, v)
+ case *int32:
+ bs = b[:4]
+ order.PutUint32(bs, uint32(*v))
+ case int32:
+ bs = b[:4]
+ order.PutUint32(bs, uint32(v))
+ case *uint32:
+ bs = b[:4]
+ order.PutUint32(bs, *v)
+ case uint32:
+ bs = b[:4]
+ order.PutUint32(bs, v)
+ case *int64:
+ bs = b[:8]
+ order.PutUint64(bs, uint64(*v))
+ case int64:
+ bs = b[:8]
+ order.PutUint64(bs, uint64(v))
+ case *uint64:
+ bs = b[:8]
+ order.PutUint64(bs, *v)
+ case uint64:
+ bs = b[:8]
+ order.PutUint64(bs, v)
+ }
+ if bs != nil {
+ _, err := w.Write(bs)
+ return err
+ }
v := reflect.Indirect(reflect.ValueOf(data))
size := TotalSize(v)
if size < 0 {
@@ -442,3 +480,19 @@ func (e *encoder) value(v reflect.Value) {
}
}
}
+
+// intDestSize returns the size of the integer that ptrType points to,
+// or 0 if the type is not supported.
+func intDestSize(ptrType interface{}) int {
+ switch ptrType.(type) {
+ case *int8, *uint8:
+ return 1
+ case *int16, *uint16:
+ return 2
+ case *int32, *uint32:
+ return 4
+ case *int64, *uint64:
+ return 8
+ }
+ return 0
+}
diff --git a/src/pkg/encoding/binary/binary_test.go b/src/pkg/encoding/binary/binary_test.go
index e588b9be41..b266996f63 100644
--- a/src/pkg/encoding/binary/binary_test.go
+++ b/src/pkg/encoding/binary/binary_test.go
@@ -201,3 +201,35 @@ func BenchmarkRead(b *testing.B) {
panic("no match")
}
}
+
+func BenchmarkWrite(b *testing.B) {
+ buf := new(bytes.Buffer)
+ var w io.Writer = buf
+
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ Write(w, BigEndian, &s.Int8)
+ Write(w, BigEndian, &s.Int16)
+ Write(w, BigEndian, &s.Int32)
+ Write(w, BigEndian, &s.Int64)
+ Write(w, BigEndian, &s.Uint8)
+ Write(w, BigEndian, &s.Uint16)
+ Write(w, BigEndian, &s.Uint32)
+ Write(w, BigEndian, &s.Uint64)
+ Write(w, BigEndian, s.Int8)
+ Write(w, BigEndian, s.Int16)
+ Write(w, BigEndian, s.Int32)
+ Write(w, BigEndian, s.Int64)
+ Write(w, BigEndian, s.Uint8)
+ Write(w, BigEndian, s.Uint16)
+ Write(w, BigEndian, s.Uint32)
+ Write(w, BigEndian, s.Uint64)
+ }
+
+ if !bytes.Equal(buf.Bytes()[:30], big[:30]) {
+ panic("first half doesn't match")
+ }
+ if !bytes.Equal(buf.Bytes()[30:], big[:30]) {
+ panic("second half doesn't match")
+ }
+}