|
|
@@ -15,19 +15,19 @@ package codec
|
|
|
// This file can be omitted without causing a build failure.
|
|
|
//
|
|
|
// The advantage of fast paths is:
|
|
|
-// - Many calls bypass reflection altogether
|
|
|
+// - Many calls bypass reflection altogether
|
|
|
//
|
|
|
// Currently support
|
|
|
-// - slice of all builtin types,
|
|
|
-// - map of all builtin types to string or interface value
|
|
|
-// - symmetrical maps of all builtin types (e.g. str-str, uint8-uint8)
|
|
|
+// - slice of all builtin types,
|
|
|
+// - map of all builtin types to string or interface value
|
|
|
+// - symmetrical maps of all builtin types (e.g. str-str, uint8-uint8)
|
|
|
// This should provide adequate "typical" implementations.
|
|
|
//
|
|
|
// Note that fast track decode functions must handle values for which an address cannot be obtained.
|
|
|
// For example:
|
|
|
-// m2 := map[string]int{}
|
|
|
-// p2 := []interface{}{m2}
|
|
|
-// // decoding into p2 will bomb if fast track functions do not treat like unaddressable.
|
|
|
+// m2 := map[string]int{}
|
|
|
+// p2 := []interface{}{m2}
|
|
|
+// // decoding into p2 will bomb if fast track functions do not treat like unaddressable.
|
|
|
//
|
|
|
|
|
|
import (
|
|
|
@@ -124,25 +124,12 @@ func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-{{/* **** removing this block, as they are never called directly ****
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+{{/*
|
|
|
**** removing this block, as they are never called directly ****
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
+**** removing this block, as they are never called directly ****
|
|
|
|
|
|
|
|
|
|
|
|
@@ -178,24 +165,15 @@ func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
**** removing this block, as they are never called directly ****
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+**** removing this block, as they are never called directly ****
|
|
|
*/}}
|
|
|
|
|
|
// -- -- fast path functions
|
|
|
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
|
|
|
-
|
|
|
func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) {
|
|
|
if f.ti.mbs {
|
|
|
fastpathTV.{{ .MethodNamePfx "EncAsMap" false }}V(rv2i(rv).([]{{ .Elem }}), e)
|
|
|
@@ -213,7 +191,6 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, e *Encoder
|
|
|
}
|
|
|
ee.WriteArrayEnd()
|
|
|
}
|
|
|
-
|
|
|
func (_ fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, e *Encoder) {
|
|
|
ee, esep := e.e, e.hh.hasElemSeparators()
|
|
|
if len(v)%2 == 1 {
|
|
|
@@ -233,11 +210,9 @@ func (_ fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, e *En
|
|
|
}
|
|
|
ee.WriteMapEnd()
|
|
|
}
|
|
|
-
|
|
|
{{end}}{{end}}{{end}}
|
|
|
|
|
|
{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
|
|
|
-
|
|
|
func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) {
|
|
|
fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), e)
|
|
|
}
|
|
|
@@ -298,27 +273,37 @@ func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Ele
|
|
|
}
|
|
|
ee.WriteMapEnd()
|
|
|
}
|
|
|
-
|
|
|
{{end}}{{end}}{{end}}
|
|
|
|
|
|
// -- decode
|
|
|
|
|
|
// -- -- fast path type switch
|
|
|
func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
|
|
|
+ var changed bool
|
|
|
switch v := iv.(type) {
|
|
|
{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}}
|
|
|
case []{{ .Elem }}:
|
|
|
- fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, false, d)
|
|
|
+ var v2 []{{ .Elem }}
|
|
|
+ v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, false, d)
|
|
|
+ if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) {
|
|
|
+ copy(v, v2)
|
|
|
+ }
|
|
|
case *[]{{ .Elem }}:
|
|
|
- if v2, changed2 := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d); changed2 {
|
|
|
+ var v2 []{{ .Elem }}
|
|
|
+ v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d)
|
|
|
+ if changed {
|
|
|
*v = v2
|
|
|
}{{/*
|
|
|
*/}}{{end}}{{end}}{{end}}{{end}}
|
|
|
-{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
|
|
|
+{{range .Values}}{{if not .Primitive}}{{if .MapKey }}{{/*
|
|
|
+// maps only change if nil, and in that case, there's no point copying
|
|
|
+*/}}
|
|
|
case map[{{ .MapKey }}]{{ .Elem }}:
|
|
|
fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, false, d)
|
|
|
case *map[{{ .MapKey }}]{{ .Elem }}:
|
|
|
- if v2, changed2 := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d); changed2 {
|
|
|
+ var v2 map[{{ .MapKey }}]{{ .Elem }}
|
|
|
+ v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d)
|
|
|
+ if changed {
|
|
|
*v = v2
|
|
|
}{{/*
|
|
|
*/}}{{end}}{{end}}{{end}}
|
|
|
@@ -354,38 +339,36 @@ Slices can change if they
|
|
|
- are addressable (from a ptr)
|
|
|
- are settable (e.g. contained in an interface{})
|
|
|
*/}}
|
|
|
-func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
|
|
|
+func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
|
|
|
if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr {
|
|
|
- var vp = rv2i(rv).(*[]{{ .Elem }})
|
|
|
- if v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, !array, d); changed {
|
|
|
- *vp = v
|
|
|
- }
|
|
|
+ vp := rv2i(rv).(*[]{{ .Elem }})
|
|
|
+ v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, !array, d)
|
|
|
+ if changed { *vp = v }
|
|
|
} else {
|
|
|
- fastpathTV.{{ .MethodNamePfx "Dec" false }}V(rv2i(rv).([]{{ .Elem }}), !array, d)
|
|
|
+ v := rv2i(rv).([]{{ .Elem }})
|
|
|
+ v2, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, !array, d)
|
|
|
+ if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) {
|
|
|
+ copy(v, v2)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, d *Decoder) {
|
|
|
- if v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed {
|
|
|
- *vp = v
|
|
|
- }
|
|
|
+ v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d)
|
|
|
+ if changed { *vp = v }
|
|
|
}
|
|
|
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, canChange bool, d *Decoder) (_ []{{ .Elem }}, changed bool) {
|
|
|
- dd := d.d
|
|
|
- {{/* // if dd.isContainerType(valueTypeNil) { dd.TryDecodeAsNil() */}}
|
|
|
+ dd := d.d{{/*
|
|
|
+ // if dd.isContainerType(valueTypeNil) { dd.TryDecodeAsNil()
|
|
|
+ */}}
|
|
|
slh, containerLenS := d.decSliceHelperStart()
|
|
|
if containerLenS == 0 {
|
|
|
if canChange {
|
|
|
- if v == nil {
|
|
|
- v = []{{ .Elem }}{}
|
|
|
- } else if len(v) != 0 {
|
|
|
- v = v[:0]
|
|
|
- }
|
|
|
+ if v == nil { v = []{{ .Elem }}{} } else if len(v) != 0 { v = v[:0] }
|
|
|
changed = true
|
|
|
}
|
|
|
slh.End()
|
|
|
return v, changed
|
|
|
}
|
|
|
-
|
|
|
hasLen := containerLenS > 0
|
|
|
var xlen int
|
|
|
if hasLen && canChange {
|
|
|
@@ -404,7 +387,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, canChange
|
|
|
}
|
|
|
j := 0
|
|
|
for ; (hasLen && j < containerLenS) || !(hasLen || dd.CheckBreak()); j++ {
|
|
|
- if j == 0 && len(v) == 0 {
|
|
|
+ if j == 0 && len(v) == 0 && canChange {
|
|
|
if hasLen {
|
|
|
xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
|
|
|
} else {
|
|
|
@@ -423,7 +406,7 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, canChange
|
|
|
d.arrayCannotExpand(len(v), j+1)
|
|
|
decodeIntoBlank = true
|
|
|
}
|
|
|
- }
|
|
|
+ }
|
|
|
slh.ElemContainerState(j)
|
|
|
if decodeIntoBlank {
|
|
|
d.swallow()
|
|
|
@@ -445,10 +428,8 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, canChange
|
|
|
slh.End()
|
|
|
return v, changed
|
|
|
}
|
|
|
-
|
|
|
{{end}}{{end}}{{end}}
|
|
|
|
|
|
-
|
|
|
{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
|
|
|
{{/*
|
|
|
Maps can change if they are
|
|
|
@@ -458,22 +439,21 @@ Maps can change if they are
|
|
|
func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
|
|
|
if rv.Kind() == reflect.Ptr {
|
|
|
vp := rv2i(rv).(*map[{{ .MapKey }}]{{ .Elem }})
|
|
|
- if v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed {
|
|
|
- *vp = v
|
|
|
- }
|
|
|
- return
|
|
|
- }
|
|
|
- fastpathTV.{{ .MethodNamePfx "Dec" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), false, d)
|
|
|
+ v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d);
|
|
|
+ if changed { *vp = v }
|
|
|
+ } else {
|
|
|
+ fastpathTV.{{ .MethodNamePfx "Dec" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), false, d)
|
|
|
+ }
|
|
|
}
|
|
|
func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .Elem }}, d *Decoder) {
|
|
|
- if v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed {
|
|
|
- *vp = v
|
|
|
- }
|
|
|
+ v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d)
|
|
|
+ if changed { *vp = v }
|
|
|
}
|
|
|
func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, canChange bool,
|
|
|
d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) {
|
|
|
- dd, esep := d.d, d.hh.hasElemSeparators()
|
|
|
- {{/* // if dd.isContainerType(valueTypeNil) {dd.TryDecodeAsNil() */}}
|
|
|
+ dd, esep := d.d, d.hh.hasElemSeparators(){{/*
|
|
|
+ // if dd.isContainerType(valueTypeNil) {dd.TryDecodeAsNil()
|
|
|
+ */}}
|
|
|
containerLen := dd.ReadMapStart()
|
|
|
if canChange && v == nil {
|
|
|
xlen := decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }})
|
|
|
@@ -484,8 +464,8 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Ele
|
|
|
dd.ReadMapEnd()
|
|
|
return v, changed
|
|
|
}
|
|
|
- {{ if eq .Elem "interface{}" }}mapGet := !d.h.MapValueReset && !d.h.InterfaceReset{{end}}
|
|
|
- var mk {{ .MapKey }}
|
|
|
+ {{ if eq .Elem "interface{}" }}mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset
|
|
|
+ {{end}}var mk {{ .MapKey }}
|
|
|
var mv {{ .Elem }}
|
|
|
hasLen := containerLen > 0
|
|
|
for j := 0; (hasLen && j < containerLen) || !(hasLen || dd.CheckBreak()); j++ {
|
|
|
@@ -497,17 +477,14 @@ func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Ele
|
|
|
}{{ else }}mk = {{ decmd .MapKey }}{{ end }}
|
|
|
if esep { dd.ReadMapElemValue() }
|
|
|
if dd.TryDecodeAsNil() {
|
|
|
- if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = {{ zerocmd .Elem }} }
|
|
|
+ if v == nil {} else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = {{ zerocmd .Elem }} }
|
|
|
continue
|
|
|
}
|
|
|
{{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
|
|
|
d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
|
|
|
- if v != nil {
|
|
|
- v[mk] = mv
|
|
|
- }
|
|
|
+ if v != nil { v[mk] = mv }
|
|
|
}
|
|
|
dd.ReadMapEnd()
|
|
|
return v, changed
|
|
|
}
|
|
|
-
|
|
|
{{end}}{{end}}{{end}}
|