mirror of
https://github.com/golang/go
synced 2024-11-14 08:30:25 -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:
parent
c0decc35ae
commit
3648a03b3a
@ -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:
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user