// //+build ignore // Copyright (c) 2012-2015 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. // ************************************************************ // DO NOT EDIT. // THIS FILE IS AUTO-GENERATED from fast-path.go.tmpl // ************************************************************ package codec // Fast path functions try to create a fast path encode or decode implementation // for common maps and slices. // // We define the functions and register then in this single file // so as not to pollute the encode.go and decode.go, and create a dependency in there. // This file can be omitted without causing a build failure. // // The advantage of fast paths is: // - Many calls bypass reflection altogether // // Currently support // - slice of all builtin types, // - map of all builtin types to string or interface value // - symetrical 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. // import ( "reflect" "sort" ) const fastpathCheckNilFalse = false // for reflect const fastpathCheckNilTrue = true // for type switch type fastpathT struct {} var fastpathTV fastpathT type fastpathE struct { rtid uintptr rt reflect.Type encfn func(encFnInfo, reflect.Value) decfn func(decFnInfo, reflect.Value) } type fastpathA [{{ .FastpathLen }}]fastpathE func (x *fastpathA) index(rtid uintptr) int { // use binary search to grab the index (adapted from sort/search.go) h, i, j := 0, 0, {{ .FastpathLen }} // len(x) for i < j { h = i + (j-i)/2 if x[h].rtid < rtid { i = h + 1 } else { j = h } } if i < {{ .FastpathLen }} && x[i].rtid == rtid { return i } return -1 } type fastpathAslice []fastpathE func (x fastpathAslice) Len() int { return len(x) } func (x fastpathAslice) Less(i, j int) bool { return x[i].rtid < x[j].rtid } func (x fastpathAslice) Swap(i, j int) { x[i], x[j] = x[j], x[i] } var fastpathAV fastpathA // due to possible initialization loop error, make fastpath in an init() func init() { if !fastpathEnabled { return } i := 0 fn := func(v interface{}, fe func(encFnInfo, reflect.Value), fd func(decFnInfo, reflect.Value)) (f fastpathE) { xrt := reflect.TypeOf(v) xptr := reflect.ValueOf(xrt).Pointer() fastpathAV[i] = fastpathE{xptr, xrt, fe, fd} i++ return } {{range .Values}}{{if not .Primitive}}{{if .Slice }} fn([]{{ .Elem }}(nil), (encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}} {{range .Values}}{{if not .Primitive}}{{if not .Slice }} fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}} sort.Sort(fastpathAslice(fastpathAV[:])) } // -- encode // -- -- fast path type switch func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool { switch v := iv.(type) { {{range .Values}}{{if not .Primitive}}{{if .Slice }} case []{{ .Elem }}:{{else}} case map[{{ .MapKey }}]{{ .Elem }}:{{end}} fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e){{if .Slice }} case *[]{{ .Elem }}:{{else}} case *map[{{ .MapKey }}]{{ .Elem }}:{{end}} fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e) {{end}}{{end}} default: return false } return true } func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool { switch v := iv.(type) { {{range .Values}}{{if not .Primitive}}{{if .Slice }} case []{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e) case *[]{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e) {{end}}{{end}}{{end}} default: return false } return true } func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool { switch v := iv.(type) { {{range .Values}}{{if not .Primitive}}{{if not .Slice }} case map[{{ .MapKey }}]{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e) case *map[{{ .MapKey }}]{{ .Elem }}: fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e) {{end}}{{end}}{{end}} default: return false } return true } // -- -- fast path functions {{range .Values}}{{if not .Primitive}}{{if .Slice }} func (f encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) { fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e) } func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) { ee := e.e if checkNil && v == nil { ee.EncodeNil() return } ee.EncodeArrayStart(len(v)) if e.be { for _, v2 := range v { {{ encmd .Elem "v2"}} } } else { for j, v2 := range v { if j > 0 { ee.EncodeArrayEntrySeparator() } {{ encmd .Elem "v2"}} } ee.EncodeArrayEnd() } } {{end}}{{end}}{{end}} {{range .Values}}{{if not .Primitive}}{{if not .Slice }} func (f encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) { fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().(map[{{ .MapKey }}]{{ .Elem }}), fastpathCheckNilFalse, f.e) } func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, e *Encoder) { ee := e.e if checkNil && v == nil { ee.EncodeNil() return } ee.EncodeMapStart(len(v)) {{if eq .MapKey "string"}}asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0{{end}} if e.be { for k2, v2 := range v { {{if eq .MapKey "string"}}if asSymbols { ee.EncodeSymbol(k2) } else { ee.EncodeString(c_UTF8, k2) }{{else}}{{ encmd .MapKey "k2"}}{{end}} {{ encmd .Elem "v2"}} } } else { j := 0 for k2, v2 := range v { if j > 0 { ee.EncodeMapEntrySeparator() } {{if eq .MapKey "string"}}if asSymbols { ee.EncodeSymbol(k2) } else { ee.EncodeString(c_UTF8, k2) }{{else}}{{ encmd .MapKey "k2"}}{{end}} ee.EncodeMapKVSeparator() {{ encmd .Elem "v2"}} j++ } ee.EncodeMapEnd() } } {{end}}{{end}}{{end}} // -- decode // -- -- fast path type switch func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool { switch v := iv.(type) { {{range .Values}}{{if not .Primitive}}{{if .Slice }} case []{{ .Elem }}:{{else}} case map[{{ .MapKey }}]{{ .Elem }}:{{end}} fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, d){{if .Slice }} case *[]{{ .Elem }}:{{else}} case *map[{{ .MapKey }}]{{ .Elem }}:{{end}} v2, changed2 := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, fastpathCheckNilFalse, true, d) if changed2 { *v = v2 } {{end}}{{end}} default: return false } return true } // -- -- fast path functions {{range .Values}}{{if not .Primitive}}{{if .Slice }} {{/* 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 (f decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) { array := f.seq == seqTypeArray if !array && rv.CanAddr() { // CanSet => CanAddr + Exported vp := rv.Addr().Interface().(*[]{{ .Elem }}) v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, !array, f.d) if changed { *vp = v } } else { v := rv.Interface().([]{{ .Elem }}) fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, f.d) } } func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, checkNil bool, d *Decoder) { v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, checkNil, true, d) if changed { *vp = v } } func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil bool, canChange bool, d *Decoder) (_ []{{ .Elem }}, changed bool) { dd := d.d // if dd.isContainerType(valueTypeNil) { dd.TryDecodeAsNil() if checkNil && dd.TryDecodeAsNil() { if v != nil { changed = true } return nil, changed } slh, containerLenS := d.decSliceHelperStart() if canChange && v == nil { if containerLenS <= 0 { v = []{{ .Elem }}{} } else { v = make([]{{ .Elem }}, containerLenS, containerLenS) } changed = true } if containerLenS == 0 { if canChange && len(v) != 0 { v = v[:0] changed = true }{{/* // slh.End() // dd.ReadArrayEnd() */}} return v, changed } // for j := 0; j < containerLenS; j++ { if containerLenS > 0 { decLen := containerLenS if containerLenS > cap(v) { if canChange { s := make([]{{ .Elem }}, containerLenS, containerLenS) // copy(s, v[:cap(v)]) v = s changed = true } else { d.arrayCannotExpand(len(v), containerLenS) decLen = len(v) } } else if containerLenS != len(v) { v = v[:containerLenS] changed = true } // all checks done. cannot go past len. j := 0 for ; j < decLen; j++ { {{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }} } if !canChange { for ; j < containerLenS; j++ { d.swallow() } } } else { j := 0 for ; !dd.CheckBreak(); j++ { if j >= len(v) { if canChange { v = append(v, {{ zerocmd .Elem }}) changed = true } else { d.arrayCannotExpand(len(v), j+1) } } if j > 0 { slh.Sep(j) } if j < len(v) { // all checks done. cannot go past len. {{ if eq .Elem "interface{}" }}d.decode(&v[j]) {{ else }}v[j] = {{ decmd .Elem }}{{ end }} } else { d.swallow() } } slh.End() } return v, changed } {{end}}{{end}}{{end}} {{range .Values}}{{if not .Primitive}}{{if not .Slice }} {{/* Maps can change if they are - addressable (from a ptr) - settable (e.g. contained in an interface{}) */}} func (f decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) { if rv.CanAddr() { vp := rv.Addr().Interface().(*map[{{ .MapKey }}]{{ .Elem }}) v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, true, f.d) if changed { *vp = v } } else { v := rv.Interface().(map[{{ .MapKey }}]{{ .Elem }}) fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, f.d) } } func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, d *Decoder) { v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, checkNil, true, d) if changed { *vp = v } } func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, canChange bool, d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) { dd := d.d // if dd.isContainerType(valueTypeNil) {dd.TryDecodeAsNil() if checkNil && dd.TryDecodeAsNil() { if v != nil { changed = true } return nil, changed } containerLen := dd.ReadMapStart() if canChange && v == nil { if containerLen > 0 { v = make(map[{{ .MapKey }}]{{ .Elem }}, containerLen) } else { v = make(map[{{ .MapKey }}]{{ .Elem }}) // supports indefinite-length, etc } changed = true } if containerLen > 0 { for j := 0; j < containerLen; j++ { {{ if eq .MapKey "interface{}" }}var mk interface{} d.decode(&mk) if bv, bok := mk.([]byte); bok { mk = string(bv) // maps cannot have []byte as key. switch to string. }{{ else }}mk := {{ decmd .MapKey }}{{ end }} mv := v[mk] {{ if eq .Elem "interface{}" }}d.decode(&mv) {{ else }}mv = {{ decmd .Elem }}{{ end }} if v != nil { v[mk] = mv } } } else if containerLen < 0 { for j := 0; !dd.CheckBreak(); j++ { if j > 0 { dd.ReadMapEntrySeparator() } {{ if eq .MapKey "interface{}" }}var mk interface{} d.decode(&mk) if bv, bok := mk.([]byte); bok { mk = string(bv) // maps cannot have []byte as key. switch to string. }{{ else }}mk := {{ decmd .MapKey }}{{ end }} dd.ReadMapKVSeparator() mv := v[mk] {{ if eq .Elem "interface{}" }}d.decode(&mv) {{ else }}mv = {{ decmd .Elem }}{{ end }} if v != nil { v[mk] = mv } } dd.ReadMapEnd() } return v, changed } {{end}}{{end}}{{end}}