]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/binary: add a non-reflect fast path for Read
authorBrad Fitzpatrick <bradfitz@golang.org>
Thu, 26 May 2011 16:01:05 +0000 (09:01 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Thu, 26 May 2011 16:01:05 +0000 (09:01 -0700)
before/after:
binary.BenchmarkRead  200000     10860 ns/op
binary.BenchmarkRead  500000      2846 ns/op

R=rsc
CC=golang-dev
https://golang.org/cl/4547062

src/pkg/encoding/binary/binary.go
src/pkg/encoding/binary/binary_test.go

index a01d0e024642166391964747a8507380e4afba69..d0185ebb71ded0b66f6d83524f3286bd32b12dcf 100644 (file)
@@ -125,6 +125,54 @@ 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]
+               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
        switch d := reflect.ValueOf(data); d.Kind() {
        case reflect.Ptr:
index 7857c68d36e009ec837ba3d22615c7f91f2ce13f..e588b9be41cc36273fe730ef51d86d0ac7f32ec5 100644 (file)
@@ -5,6 +5,7 @@
 package binary
 
 import (
+       "io"
        "os"
        "bytes"
        "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")
+       }
+}