1
0
mirror of https://github.com/golang/go synced 2024-11-25 06:57:58 -07:00

encoding/binary: add a non-reflect fast path for Read

before/after:
binary.BenchmarkRead  200000     10860 ns/op
binary.BenchmarkRead  500000      2846 ns/op

R=rsc
CC=golang-dev
https://golang.org/cl/4547062
This commit is contained in:
Brad Fitzpatrick 2011-05-26 09:01:05 -07:00
parent c0decc35ae
commit 3648a03b3a
2 changed files with 89 additions and 0 deletions

View File

@ -125,6 +125,54 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// Bytes read from r are decoded using the specified byte order // Bytes read from r are decoded using the specified byte order
// and written to successive fields of the data. // and written to successive fields of the data.
func Read(r io.Reader, order ByteOrder, data interface{}) os.Error { 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]
if _, err := io.ReadFull(r, bs); err != nil {
return err
}
switch v := data.(type) {
case *int8:
*v = int8(buf[0])
case *uint8:
*v = buf[0]
case *int16:
*v = int16(order.Uint16(bs))
case *uint16:
*v = order.Uint16(bs)
case *int32:
*v = int32(order.Uint32(bs))
case *uint32:
*v = order.Uint32(bs)
case *int64:
*v = int64(order.Uint64(bs))
case *uint64:
*v = order.Uint64(bs)
}
return nil
}
// Fallback to reflect-based.
var v reflect.Value var v reflect.Value
switch d := reflect.ValueOf(data); d.Kind() { switch d := reflect.ValueOf(data); d.Kind() {
case reflect.Ptr: case reflect.Ptr:

View File

@ -5,6 +5,7 @@
package binary package binary
import ( import (
"io"
"os" "os"
"bytes" "bytes"
"math" "math"
@ -160,3 +161,43 @@ func TestWriteT(t *testing.T) {
} }
} }
} }
type byteSliceReader struct {
remain []byte
}
func (br *byteSliceReader) Read(p []byte) (int, os.Error) {
n := copy(p, br.remain)
br.remain = br.remain[n:]
return n, nil
}
func BenchmarkRead(b *testing.B) {
var ls Struct
bsr := &byteSliceReader{}
var r io.Reader = bsr
for i := 0; i < b.N; i++ {
bsr.remain = big
Read(r, BigEndian, &ls.Int8)
Read(r, BigEndian, &ls.Int16)
Read(r, BigEndian, &ls.Int32)
Read(r, BigEndian, &ls.Int64)
Read(r, BigEndian, &ls.Uint8)
Read(r, BigEndian, &ls.Uint16)
Read(r, BigEndian, &ls.Uint32)
Read(r, BigEndian, &ls.Uint64)
}
want := s
want.Float32 = 0
want.Float64 = 0
want.Complex64 = 0
want.Complex128 = 0
for i := range want.Array {
want.Array[i] = 0
}
if !reflect.DeepEqual(ls, want) {
panic("no match")
}
}