aboutsummaryrefslogtreecommitdiff
path: root/src/encoding/gob/decode.go
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2014-10-17 12:37:41 -0700
committerRob Pike <r@golang.org>2014-10-17 12:37:41 -0700
commit9965e4022030f56fc241be8934d5e6b95ac84900 (patch)
tree08efd013bcfb057a883b25c61df1e379afee721f /src/encoding/gob/decode.go
parentf4de59e234bfa7fb2a3a86764f390b09d4249a9b (diff)
downloadgo-9965e4022030f56fc241be8934d5e6b95ac84900.tar.gz
go-9965e4022030f56fc241be8934d5e6b95ac84900.zip
encoding/gob: custom array/slice decoders
Use go generate to write better loops for decoding arrays, just as we did for encoding. It doesn't help as much, relatively speaking, but it's still noticeable. benchmark old ns/op new ns/op delta BenchmarkDecodeComplex128Slice 202348 184529 -8.81% BenchmarkDecodeFloat64Slice 135800 120979 -10.91% BenchmarkDecodeInt32Slice 121200 105149 -13.24% BenchmarkDecodeStringSlice 288129 278214 -3.44% LGTM=rsc R=rsc CC=golang-codereviews https://golang.org/cl/154420044
Diffstat (limited to 'src/encoding/gob/decode.go')
-rw-r--r--src/encoding/gob/decode.go33
1 files changed, 21 insertions, 12 deletions
diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go
index 6a9213fb3c..f44838e4cf 100644
--- a/src/encoding/gob/decode.go
+++ b/src/encoding/gob/decode.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+//go:generate go run decgen.go -output dec_helpers.go
+
package gob
import (
@@ -19,6 +21,8 @@ var (
errRange = errors.New("gob: bad data: field numbers out of bounds")
)
+type decHelper func(state *decoderState, v reflect.Value, length int, ovfl error) bool
+
// decoderState is the execution state of an instance of the decoder. A new state
// is created for nested objects.
type decoderState struct {
@@ -257,7 +261,7 @@ func float64FromBits(u uint64) float64 {
// number, and returns it. It's a helper function for float32 and complex64.
// It returns a float64 because that's what reflection needs, but its return
// value is known to be accurately representable in a float32.
-func float32FromBits(i *decInstr, u uint64) float64 {
+func float32FromBits(u uint64, ovfl error) float64 {
v := float64FromBits(u)
av := v
if av < 0 {
@@ -265,7 +269,7 @@ func float32FromBits(i *decInstr, u uint64) float64 {
}
// +Inf is OK in both 32- and 64-bit floats. Underflow is always OK.
if math.MaxFloat32 < av && av <= math.MaxFloat64 {
- error_(i.ovfl)
+ error_(ovfl)
}
return v
}
@@ -273,7 +277,7 @@ func float32FromBits(i *decInstr, u uint64) float64 {
// decFloat32 decodes an unsigned integer, treats it as a 32-bit floating-point
// number, and stores it in value.
func decFloat32(i *decInstr, state *decoderState, value reflect.Value) {
- value.SetFloat(float32FromBits(i, state.decodeUint()))
+ value.SetFloat(float32FromBits(state.decodeUint(), i.ovfl))
}
// decFloat64 decodes an unsigned integer, treats it as a 64-bit floating-point
@@ -286,8 +290,8 @@ func decFloat64(i *decInstr, state *decoderState, value reflect.Value) {
// pair of floating point numbers, and stores them as a complex64 in value.
// The real part comes first.
func decComplex64(i *decInstr, state *decoderState, value reflect.Value) {
- real := float32FromBits(i, state.decodeUint())
- imag := float32FromBits(i, state.decodeUint())
+ real := float32FromBits(state.decodeUint(), i.ovfl)
+ imag := float32FromBits(state.decodeUint(), i.ovfl)
value.SetComplex(complex(real, imag))
}
@@ -450,7 +454,10 @@ func (dec *Decoder) ignoreSingle(engine *decEngine) {
}
// decodeArrayHelper does the work for decoding arrays and slices.
-func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error) {
+func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) {
+ if helper != nil && helper(state, value, length, ovfl) {
+ return
+ }
instr := &decInstr{elemOp, 0, nil, ovfl}
isPtr := value.Type().Elem().Kind() == reflect.Ptr
for i := 0; i < length; i++ {
@@ -468,11 +475,11 @@ func (dec *Decoder) decodeArrayHelper(state *decoderState, value reflect.Value,
// decodeArray decodes an array and stores it in value.
// The length is an unsigned integer preceding the elements. Even though the length is redundant
// (it's part of the type), it's a useful check and is included in the encoding.
-func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error) {
+func (dec *Decoder) decodeArray(atyp reflect.Type, state *decoderState, value reflect.Value, elemOp decOp, length int, ovfl error, helper decHelper) {
if n := state.decodeUint(); n != uint64(length) {
errorf("length mismatch in decodeArray")
}
- dec.decodeArrayHelper(state, value, elemOp, length, ovfl)
+ dec.decodeArrayHelper(state, value, elemOp, length, ovfl, helper)
}
// decodeIntoValue is a helper for map decoding.
@@ -534,7 +541,7 @@ func (dec *Decoder) ignoreMap(state *decoderState, keyOp, elemOp decOp) {
// decodeSlice decodes a slice and stores it in value.
// Slices are encoded as an unsigned length followed by the elements.
-func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, ovfl error) {
+func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp decOp, ovfl error, helper decHelper) {
u := state.decodeUint()
typ := value.Type()
size := uint64(typ.Elem().Size())
@@ -551,7 +558,7 @@ func (dec *Decoder) decodeSlice(state *decoderState, value reflect.Value, elemOp
} else {
value.Set(value.Slice(0, n))
}
- dec.decodeArrayHelper(state, value, elemOp, n, ovfl)
+ dec.decodeArrayHelper(state, value, elemOp, n, ovfl, helper)
}
// ignoreSlice skips over the data for a slice value with no destination.
@@ -720,8 +727,9 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
elemId := dec.wireType[wireId].ArrayT.Elem
elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress)
ovfl := overflow(name)
+ helper := decArrayHelper[t.Elem().Kind()]
op = func(i *decInstr, state *decoderState, value reflect.Value) {
- state.dec.decodeArray(t, state, value, *elemOp, t.Len(), ovfl)
+ state.dec.decodeArray(t, state, value, *elemOp, t.Len(), ovfl, helper)
}
case reflect.Map:
@@ -748,8 +756,9 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
}
elemOp := dec.decOpFor(elemId, t.Elem(), name, inProgress)
ovfl := overflow(name)
+ helper := decSliceHelper[t.Elem().Kind()]
op = func(i *decInstr, state *decoderState, value reflect.Value) {
- state.dec.decodeSlice(state, value, *elemOp, ovfl)
+ state.dec.decodeSlice(state, value, *elemOp, ovfl, helper)
}
case reflect.Struct: