aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/encoding/binary
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2013-08-10 08:40:32 +1000
committerRob Pike <r@golang.org>2013-08-10 08:40:32 +1000
commit1f25f5ad48b61092bdd8f43af7c068db0e947363 (patch)
tree5554a67851a89fc1a7905b2319c0bcc42388652c /src/pkg/encoding/binary
parentd9f93b0e0b351de6cfe05c03d8e8f78328178407 (diff)
downloadgo-1f25f5ad48b61092bdd8f43af7c068db0e947363.tar.xz
encoding/binary: fast path for reading slices
Again, it still allocates but the code is simple. benchmark old ns/op new ns/op delta BenchmarkReadSlice1000Int32s 35580 11465 -67.78% benchmark old MB/s new MB/s speedup BenchmarkReadSlice1000Int32s 112.42 348.86 3.10x R=golang-dev, bradfitz CC=golang-dev https://golang.org/cl/12694048
Diffstat (limited to 'src/pkg/encoding/binary')
-rw-r--r--src/pkg/encoding/binary/binary.go82
1 files changed, 67 insertions, 15 deletions
diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go
index 28fc09480e..107b80b9fe 100644
--- a/src/pkg/encoding/binary/binary.go
+++ b/src/pkg/encoding/binary/binary.go
@@ -134,30 +134,67 @@ func (bigEndian) GoString() string { return "binary.BigEndian" }
// blank (_) field names is skipped; i.e., blank field names
// may be used for padding.
func Read(r io.Reader, order ByteOrder, data interface{}) error {
- // Fast path for basic types.
+ // Fast path for basic types and slices.
if n := intDestSize(data); n != 0 {
var b [8]byte
- bs := b[:n]
+ var bs []byte
+ if n > len(b) {
+ bs = make([]byte, n)
+ } else {
+ bs = b[:n]
+ }
if _, err := io.ReadFull(r, bs); err != nil {
return err
}
- switch v := data.(type) {
+ switch data := data.(type) {
case *int8:
- *v = int8(b[0])
+ *data = int8(b[0])
case *uint8:
- *v = b[0]
+ *data = b[0]
case *int16:
- *v = int16(order.Uint16(bs))
+ *data = int16(order.Uint16(bs))
case *uint16:
- *v = order.Uint16(bs)
+ *data = order.Uint16(bs)
case *int32:
- *v = int32(order.Uint32(bs))
+ *data = int32(order.Uint32(bs))
case *uint32:
- *v = order.Uint32(bs)
+ *data = order.Uint32(bs)
case *int64:
- *v = int64(order.Uint64(bs))
+ *data = int64(order.Uint64(bs))
case *uint64:
- *v = order.Uint64(bs)
+ *data = order.Uint64(bs)
+ case []int8:
+ for i, x := range bs { // Easier to loop over the input for 8-bit cases.
+ data[i] = int8(x)
+ }
+ case []uint8:
+ for i, x := range bs { // Easier to loop over the input for 8-bit cases.
+ data[i] = x
+ }
+ case []int16:
+ for i := range data {
+ data[i] = int16(order.Uint16(bs[2*i:]))
+ }
+ case []uint16:
+ for i := range data {
+ data[i] = order.Uint16(bs[2*i:])
+ }
+ case []int32:
+ for i := range data {
+ data[i] = int32(order.Uint32(bs[4*i:]))
+ }
+ case []uint32:
+ for i := range data {
+ data[i] = order.Uint32(bs[4*i:])
+ }
+ case []int64:
+ for i := range data {
+ data[i] = int64(order.Uint64(bs[8*i:]))
+ }
+ case []uint64:
+ for i := range data {
+ data[i] = order.Uint64(bs[8*i:])
+ }
}
return nil
}
@@ -572,18 +609,33 @@ func (e *encoder) skip(v reflect.Value) {
e.buf = e.buf[n:]
}
-// 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) {
+// intDestSize returns the size of the data required to represent the data when encoded.
+func intDestSize(data interface{}) int {
+ switch data := data.(type) {
case *int8, *uint8:
return 1
+ case []int8:
+ return len(data)
+ case []uint8:
+ return len(data)
case *int16, *uint16:
return 2
+ case []int16:
+ return 2 * len(data)
+ case []uint16:
+ return 2 * len(data)
case *int32, *uint32:
return 4
+ case []int32:
+ return 4 * len(data)
+ case []uint32:
+ return 4 * len(data)
case *int64, *uint64:
return 8
+ case []int64:
+ return 8 * len(data)
+ case []uint64:
+ return 8 * len(data)
}
return 0
}