Browse Source

codec: streamline and optimize fast-path functions

    Since we know statically whether the array or slice or map can be changed,
    we can dispatch to an appropriate function directly.

    This reduces function overhead and extra work done in each loop.
Ugorji Nwoke 6 năm trước cách đây
mục cha
commit
79e5e7c841
2 tập tin đã thay đổi với 475 bổ sung659 xóa
  1. 361 521
      codec/fast-path.generated.go
  2. 114 138
      codec/fast-path.go.tmpl

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 361 - 521
codec/fast-path.generated.go


+ 114 - 138
codec/fast-path.go.tmpl

@@ -95,11 +95,13 @@ func init() {
 		i++
 	}
 	{{/* do not register []uint8 in fast-path */}}
-	{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}}
-	fn([]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}{{end}}
+	{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8" -}}
+	fn([]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R)
+	{{end}}{{end}}{{end}}{{end}}
 	
-	{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
-	fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
+	{{range .Values}}{{if not .Primitive}}{{if .MapKey -}}
+	fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R)
+	{{end}}{{end}}{{end}}
 	
 	sort.Sort(fastpathAslice(fastpathAV[:]))
 }
@@ -109,60 +111,20 @@ func init() {
 // -- -- fast path type switch
 func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
 	switch v := iv.(type) {
-
-{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}}
-	case []{{ .Elem }}:
-		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
-	case *[]{{ .Elem }}:
-		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e){{/*
-*/}}{{end}}{{end}}{{end}}{{end}}
-
-{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
-	case map[{{ .MapKey }}]{{ .Elem }}:
-		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
-	case *map[{{ .MapKey }}]{{ .Elem }}:
-		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e){{/*
-*/}}{{end}}{{end}}{{end}}
-
-	default:
-		_ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
-		return false
-	}
-	return true
-}
-
-{{/*
-**** removing this block, as they are never called directly ****
-
-
-
-**** removing this block, as they are never called directly ****
-
-
-
-func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
-	switch v := iv.(type) {
-{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
+{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8" -}}
 	case []{{ .Elem }}:
 		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
 	case *[]{{ .Elem }}:
 		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
-{{end}}{{end}}{{end}}
-	default:
-		_ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
-		return false
-	}
-	return true
-}
+{{end}}{{end}}{{end}}{{end -}}
 
-func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
-	switch v := iv.(type) {
-{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
+{{range .Values}}{{if not .Primitive}}{{if .MapKey -}}
 	case map[{{ .MapKey }}]{{ .Elem }}:
 		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
 	case *map[{{ .MapKey }}]{{ .Elem }}:
 		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
-{{end}}{{end}}{{end}}
+{{end}}{{end}}{{end -}}
+
 	default:
 		_ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
 		return false
@@ -170,17 +132,8 @@ func fastpathEncodeTypeSwitchMap(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 ****
-*/}}
-
 // -- -- fast path functions
-{{range .Values}}{{if not .Primitive}}{{if not .MapKey }} 
+{{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)
@@ -218,9 +171,9 @@ func (fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, e *Enco
 		e.mapEnd()
 	}
 }
-{{end}}{{end}}{{end}}
+{{end}}{{end}}{{end -}}
 
-{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
+{{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)
 }
@@ -271,40 +224,36 @@ func (fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem
 	}
 	e.mapEnd()
 }
-{{end}}{{end}}{{end}}
+{{end}}{{end}}{{end -}}
 
 // -- decode
 
 // -- -- fast path type switch
 func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
-	 var changed bool
+	var changed bool
+	var containerLen int
 	switch v := iv.(type) {
-{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}}
+{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8" -}}
 	case []{{ .Elem }}:
-		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)
-		}
+		fastpathTV.{{ .MethodNamePfx "Dec" false }}N(v, d)
 	case *[]{{ .Elem }}:
 		var v2 []{{ .Elem }}
-		v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d)
-		if changed {
+		if v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}Y(*v, d); changed {
 			*v = v2 
-		}{{/*
-*/}}{{end}}{{end}}{{end}}{{end}}
+		}
+{{end}}{{end}}{{end}}{{end -}}
 {{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)
+		fastpathTV.{{ .MethodNamePfx "Dec" false }}L(v, d.mapStart(), d)
 	case *map[{{ .MapKey }}]{{ .Elem }}:
-		 var v2 map[{{ .MapKey }}]{{ .Elem }}
-		v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d)
-		if changed {
-			*v = v2 
-		}{{/*
-*/}}{{end}}{{end}}{{end}}
+		containerLen = d.mapStart()
+		if *v == nil {
+			*v = make(map[{{ .MapKey }}]{{ .Elem }}, decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }}))
+		}
+		fastpathTV.{{ .MethodNamePfx "Dec" false }}L(*v, containerLen, d)
+{{end}}{{end}}{{end -}}
 	default:
 		_ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
 		return false
@@ -314,14 +263,14 @@ func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
 
 func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool {
 	switch v := iv.(type) {
-{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
+{{range .Values}}{{if not .Primitive}}{{if not .MapKey -}}
 	case *[]{{ .Elem }}: 
-		*v = nil {{/*
-*/}}{{end}}{{end}}{{end}}
-{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
+		*v = nil
+{{end}}{{end}}{{end}}
+{{range .Values}}{{if not .Primitive}}{{if .MapKey -}}
 	case *map[{{ .MapKey }}]{{ .Elem }}: 
-		*v = nil {{/*
-*/}}{{end}}{{end}}{{end}}
+		*v = nil 
+{{end}}{{end}}{{end}}
 	default:
 		_ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
 		return false
@@ -330,44 +279,37 @@ func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool {
 }
 
 // -- -- fast path functions
-{{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
+{{range .Values}}{{if not .Primitive}}{{if not .MapKey -}}
 {{/*
-Slices can change if they 
+Slices can change if they
 - did not come from an array
 - 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) {
-	if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr {
+	if f.seq != seqTypeArray && rv.Kind() == reflect.Ptr {
 		vp := rv2i(rv).(*[]{{ .Elem }})
-		if v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, !array, d); changed { *vp = v }
+		if v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}Y(*vp, d); changed { *vp = v }
 	} else {
-		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)
-		}
+		fastpathTV.{{ .MethodNamePfx "Dec" false }}N(rv2i(rv).([]{{ .Elem }}), d)
 	}
 }
 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 }
+	if v, changed := f.{{ .MethodNamePfx "Dec" false }}Y(*vp, d); changed { *vp = v }
 }
-func (fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, canChange bool, d *Decoder) (_ []{{ .Elem }}, changed bool) {
+func (fastpathT) {{ .MethodNamePfx "Dec" false }}Y(v []{{ .Elem }}, d *Decoder) (_ []{{ .Elem }}, changed bool) {
 	{{/* dd := d.d
 		// if d.d.isContainerType(valueTypeNil) { d.d.TryDecodeAsNil() }
 	 */ -}}
 	slh, containerLenS := d.decSliceHelperStart()
 	if containerLenS == 0 {
-		if canChange {
-			if v == nil { v = []{{ .Elem }}{} } else if len(v) != 0 { v = v[:0] }
-			changed = true
-		}
+		if v == nil { v = []{{ .Elem }}{} } else if len(v) != 0 { v = v[:0] }
 		slh.End()
-		return v, changed
+		return v, true
 	}
 	hasLen := containerLenS > 0
 	var xlen int 
-	if hasLen && canChange {
+	if hasLen {
 		if containerLenS > cap(v) {
 			xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
 			if xlen <= cap(v) {
@@ -383,7 +325,7 @@ func (fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, canChange bo
 	}
 	var j int
 	for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ {
-		if j == 0 && len(v) == 0 && canChange {
+		if j == 0 && len(v) == 0 {
 			if hasLen {
 				xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
 			} else {
@@ -393,69 +335,104 @@ func (fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, canChange bo
 			changed = true 
 		}
 		{{/* // if indefinite, etc, then expand the slice if necessary */ -}}
-		var decodeIntoBlank bool
 		if j >= len(v) {
-			if canChange {
-				v = append(v, {{ zerocmd .Elem }})
-				changed = true
-			} else {
-				d.arrayCannotExpand(len(v), j+1)
-				decodeIntoBlank = true
-			}
+			v = append(v, {{ zerocmd .Elem }})
+			changed = true
 		} 
 		slh.ElemContainerState(j)
-		if decodeIntoBlank {
-			d.swallow()
-		} else if d.d.TryDecodeAsNil() {
+		if d.d.TryDecodeAsNil() {
 			v[uint(j)] = {{ zerocmd .Elem }}
 		} else {
 			{{ if eq .Elem "interface{}" }}d.decode(&v[uint(j)]){{ else }}v[uint(j)] = {{ decmd .Elem }}{{ end }}
 		}
 	}
-	if canChange {
-		if j < len(v) {
-			v = v[:uint(j)]
-			changed = true
-		} else if j == 0 && v == nil {
-			v = make([]{{ .Elem }}, 0)
-			changed = true
-		}
+	if j < len(v) {
+		v = v[:uint(j)]
+		changed = true
+	} else if j == 0 && v == nil {
+		v = []{{ .Elem }}{}
+		changed = true
 	}
 	slh.End()
 	return v, changed 
 }
-{{end}}{{end}}{{end}}
+func (fastpathT) {{ .MethodNamePfx "Dec" false }}N(v []{{ .Elem }}, d *Decoder) {
+	{{/* dd := d.d
+		// if d.d.isContainerType(valueTypeNil) { d.d.TryDecodeAsNil() }
+	 */ -}}
+	slh, containerLenS := d.decSliceHelperStart()
+	if containerLenS == 0 {
+		slh.End()
+		return
+	}
+	hasLen := containerLenS > 0
+	for j := 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ {
+		{{/* // if indefinite, etc, then expand the slice if necessary */ -}}
+		if j >= len(v) {
+			d.arrayCannotExpand(len(v), j+1)
+			slh.ElemContainerState(j)
+			d.swallow()
+			for ; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ {
+				slh.ElemContainerState(j)
+				d.swallow()
+			}
+			break
+		} 
+		slh.ElemContainerState(j)
+		if d.d.TryDecodeAsNil() {
+			v[uint(j)] = {{ zerocmd .Elem }}
+		} else {
+			{{ if eq .Elem "interface{}" }}d.decode(&v[uint(j)]){{ else }}v[uint(j)] = {{ decmd .Elem }}{{ end }}
+		}
+	}
+	slh.End()
+}
+{{end}}{{end}}{{end -}}
 
-{{range .Values}}{{if not .Primitive}}{{if .MapKey }}
+{{range .Values}}{{if not .Primitive}}{{if .MapKey -}}
 {{/*
 Maps can change if they are
 - addressable (from a ptr)
 - settable (e.g. contained in an interface{})
-*/}}
+*/ -}}
 func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
+    {{/* // if d.d.isContainerType(valueTypeNil) {d.d.TryDecodeAsNil()	*/ -}}
+	containerLen := d.mapStart()
 	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 }
+		if *vp == nil {
+			*vp = make(map[{{ .MapKey }}]{{ .Elem }}, decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }}))
+		}
+		fastpathTV.{{ .MethodNamePfx "Dec" false }}L(*vp, containerLen, d)
 	} else {
-		fastpathTV.{{ .MethodNamePfx "Dec" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), false, d)
+		fastpathTV.{{ .MethodNamePfx "Dec" false }}L(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), containerLen, 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 }
+	containerLen := d.mapStart()
+	if *vp == nil {
+		*vp = make(map[{{ .MapKey }}]{{ .Elem }}, decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }}))
+	}
+	f.{{ .MethodNamePfx "Dec" false }}L(*vp, containerLen, d)
 }
-func (fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, canChange bool, 
-	d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) {
-    {{/*
-		// if d.d.isContainerType(valueTypeNil) {d.d.TryDecodeAsNil()
-	*/ -}}
+{{/*
+func (f fastpathT) {{ .MethodNamePfx "Dec" false }}Y(v map[{{ .MapKey }}]{{ .Elem }}, d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) {
 	containerLen := d.mapStart()
-	if canChange && v == nil {
+	if v == nil {
 		v = make(map[{{ .MapKey }}]{{ .Elem }}, decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }}))
 		changed = true
 	}
+	f.{{ .MethodNamePfx "Dec" false }}L(v, containerLen, d)
+	return v, changed
+}
+func (f fastpathT) {{ .MethodNamePfx "Dec" false }}N(v map[{{ .MapKey }}]{{ .Elem }}, d *Decoder) {
+	f.{{ .MethodNamePfx "Dec" false }}L(v, d.mapStart(), d)
+}
+*/ -}}
+func (fastpathT) {{ .MethodNamePfx "Dec" false }}L(v map[{{ .MapKey }}]{{ .Elem }}, containerLen int, d *Decoder) {
 	if containerLen == 0 {
 		d.mapEnd()
-		return v, changed
+		return
 	}
 	{{if eq .Elem "interface{}" }}mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset
     {{else if eq .Elem "bytes" "[]byte" }}mapGet := v != nil && !d.h.MapValueReset
@@ -488,6 +465,5 @@ func (fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem
 		if v != nil { v[mk] = mv }
 	}
 	d.mapEnd()
-	return v, changed
 }
 {{end}}{{end}}{{end}}

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác