}
func BenchmarkCodeEncoder(b *testing.B) {
+ b.ReportAllocs()
if codeJSON == nil {
b.StopTimer()
codeInit()
}
func BenchmarkCodeMarshal(b *testing.B) {
+ b.ReportAllocs()
if codeJSON == nil {
b.StopTimer()
codeInit()
}
func BenchmarkMarshalBytes(b *testing.B) {
+ b.ReportAllocs()
// 32 fits within encodeState.scratch.
b.Run("32", benchMarshalBytes(32))
// 256 doesn't fit in encodeState.scratch, but is small enough to
}
func BenchmarkCodeDecoder(b *testing.B) {
+ b.ReportAllocs()
if codeJSON == nil {
b.StopTimer()
codeInit()
}
func BenchmarkUnicodeDecoder(b *testing.B) {
+ b.ReportAllocs()
j := []byte(`"\uD83D\uDE01"`)
b.SetBytes(int64(len(j)))
r := bytes.NewReader(j)
}
func BenchmarkDecoderStream(b *testing.B) {
+ b.ReportAllocs()
b.StopTimer()
var buf bytes.Buffer
dec := NewDecoder(&buf)
}
func BenchmarkCodeUnmarshal(b *testing.B) {
+ b.ReportAllocs()
if codeJSON == nil {
b.StopTimer()
codeInit()
}
func BenchmarkCodeUnmarshalReuse(b *testing.B) {
+ b.ReportAllocs()
if codeJSON == nil {
b.StopTimer()
codeInit()
}
func BenchmarkUnmarshalString(b *testing.B) {
+ b.ReportAllocs()
data := []byte(`"hello, world"`)
b.RunParallel(func(pb *testing.PB) {
var s string
}
func BenchmarkUnmarshalFloat64(b *testing.B) {
+ b.ReportAllocs()
data := []byte(`3.14`)
b.RunParallel(func(pb *testing.PB) {
var f float64
}
func BenchmarkUnmarshalInt64(b *testing.B) {
+ b.ReportAllocs()
data := []byte(`3`)
b.RunParallel(func(pb *testing.PB) {
var x int64
}
func BenchmarkTypeFieldsCache(b *testing.B) {
+ b.ReportAllocs()
var maxTypes int = 1e6
if testenv.Builder() != "" {
maxTypes = 1e3 // restrict cache sizes on builders
"fmt"
"reflect"
"strconv"
+ "strings"
"unicode"
"unicode/utf16"
"unicode/utf8"
opcode int // last read result
scan scanner
errorContext struct { // provides context for type errors
- Struct reflect.Type
- Field string
+ Struct reflect.Type
+ FieldStack []string
}
savedError error
useNumber bool
d.off = 0
d.savedError = nil
d.errorContext.Struct = nil
- d.errorContext.Field = ""
+
+ // Reuse the allocated space for the FieldStack slice.
+ d.errorContext.FieldStack = d.errorContext.FieldStack[:0]
return d
}
// addErrorContext returns a new error enhanced with information from d.errorContext
func (d *decodeState) addErrorContext(err error) error {
- if d.errorContext.Struct != nil || d.errorContext.Field != "" {
+ if d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0 {
switch err := err.(type) {
case *UnmarshalTypeError:
err.Struct = d.errorContext.Struct.Name()
- err.Field = d.errorContext.Field
+ err.Field = strings.Join(d.errorContext.FieldStack, ".")
return err
}
}
}
var mapElem reflect.Value
- originalErrorContext := d.errorContext
+ origErrorContext := d.errorContext
for {
// Read opening " of string key or closing }.
}
subv = subv.Field(i)
}
- if originalErrorContext.Field == "" {
- d.errorContext.Field = f.name
- } else {
- d.errorContext.Field = originalErrorContext.Field + "." + f.name
- }
+ d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name)
d.errorContext.Struct = t
} else if d.disallowUnknownFields {
d.saveError(fmt.Errorf("json: unknown field %q", key))
if d.opcode == scanSkipSpace {
d.scanWhile(scanSkipSpace)
}
+ // Reset errorContext to its original state.
+ // Keep the same underlying array for FieldStack, to reuse the
+ // space and avoid unnecessary allocs.
+ d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)]
+ d.errorContext.Struct = origErrorContext.Struct
if d.opcode == scanEndObject {
break
}
if d.opcode != scanObjectValue {
panic(phasePanicMsg)
}
-
- d.errorContext = originalErrorContext
}
return nil
}