//+build ignore // Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a BSD-style license found in the LICENSE file. package main import ( "bytes" "go/format" "os" "strings" "text/template" ) const tmplstr = ` // Copyright (c) 2012, 2013 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a BSD-style license found in the LICENSE file. // ************************************************************ // DO NOT EDIT. // THIS FILE IS GENERATED BY RUNNING: go run gen-fast-path.go // ************************************************************ 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. import ( "reflect" ) func init() { if !fastpathEnabled { return // basically disable the fast path checks (since accessing empty map is basically free) } fdx := func(i interface{}, fd func(*decFnInfo, reflect.Value)) { fastpathsDec[reflect.ValueOf(reflect.TypeOf(i)).Pointer()] = fd } fex := func(i interface{}, fe func(*encFnInfo, reflect.Value)) { fastpathsEnc[reflect.ValueOf(reflect.TypeOf(i)).Pointer()] = fe } {{range .Values}}{{if .Encode}}{{if .Slice }} fex([]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodName }}){{end}}{{end}}{{end}} {{range .Values}}{{if .Encode}}{{if not .Slice }} fex(map[{{ .MapKey }}]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodName }}){{end}}{{end}}{{end}} {{range .Values}}{{if not .Encode}}{{if .Slice }} fdx([]{{ .Elem }}(nil), (*decFnInfo).{{ .MethodName }}){{end}}{{end}}{{end}} {{range .Values}}{{if not .Encode}}{{if not .Slice }} fdx(map[{{ .MapKey }}]{{ .Elem }}(nil), (*decFnInfo).{{ .MethodName }}){{end}}{{end}}{{end}} } // -- encode {{range .Values}}{{if .Encode}}{{if .Slice }} func (f *encFnInfo) {{ .MethodName }}(rv reflect.Value) { v := rv.Interface().([]{{ .Elem }}) f.ee.encodeArrayPreamble(len(v)) for _, v2 := range v { {{ encmd .Elem "v2"}} } } {{end}}{{end}}{{end}} {{range .Values}}{{if .Encode}}{{if not .Slice }} func (f *encFnInfo) {{ .MethodName }}(rv reflect.Value) { v := rv.Interface().(map[{{ .MapKey }}]{{ .Elem }}) f.ee.encodeMapPreamble(len(v)) {{if eq .MapKey "string"}}asSymbols := f.e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0{{end}} for k2, v2 := range v { {{if eq .MapKey "string"}}if asSymbols { f.ee.encodeSymbol(k2) } else { f.ee.encodeString(c_UTF8, k2) }{{else}}{{ encmd .MapKey "k2"}}{{end}} {{ encmd .Elem "v2"}} } } {{end}}{{end}}{{end}} // -- decode {{range .Values}}{{if not .Encode}}{{if .Slice }} func (f *decFnInfo) {{ .MethodName }}(rv reflect.Value) { v := rv.Addr().Interface().(*[]{{ .Elem }}) var s []{{ .Elem }} vtype := f.dd.currentEncodedType() if vtype == valueTypeNil { *v = s return } _, containerLenS := decContLens(f.dd, vtype) s = *v if s == nil { s = make([]{{ .Elem }}, containerLenS, containerLenS) } else if containerLenS > cap(s) { if f.array { decErr(msgDecCannotExpandArr, cap(s), containerLenS) } s = make([]{{ .Elem }}, containerLenS, containerLenS) copy(s, *v) } else if containerLenS > len(s) { s = s[:containerLenS] } for j := 0; j < containerLenS; j++ { {{ if eq .Elem "interface{}" }}f.d.decode(&s[j]) {{ else }}f.dd.initReadNext() s[j] = {{ decmd .Elem }} {{ end }} } *v = s } {{end}}{{end}}{{end}} {{range .Values}}{{if not .Encode}}{{if not .Slice }} func (f *decFnInfo) {{ .MethodName }}(rv reflect.Value) { v := rv.Addr().Interface().(*map[{{ .MapKey }}]{{ .Elem }}) var m map[{{ .MapKey }}]{{ .Elem }} vtype := f.dd.currentEncodedType() if vtype == valueTypeNil { *v = m return } containerLen := f.dd.readMapLen() m = *v if m == nil { m = make(map[{{ .MapKey }}]{{ .Elem }}, containerLen) *v = m } for j := 0; j < containerLen; j++ { {{ if eq .MapKey "interface{}" }}var mk interface{} f.d.decode(&mk) // special case if a byte array. if bv, bok := mk.([]byte); bok { mk = string(bv) } {{ else }}f.dd.initReadNext() mk := {{ decmd .MapKey }} {{ end }} mv := m[mk] {{ if eq .Elem "interface{}" }}f.d.decode(&mv) {{ else }}f.dd.initReadNext() mv = {{ decmd .Elem }} {{ end }} m[mk] = mv } } {{end}}{{end}}{{end}} ` type genInfo struct { Slice bool Encode bool MapKey string Elem string } func EncCommandAsString(s string, vname string) string { switch s { case "uint", "uint8", "uint16", "uint31", "uint64": return "f.ee.encodeUint(uint64(" + vname + "))" case "int", "int8", "int16", "int31", "int64": return "f.ee.encodeInt(int64(" + vname + "))" case "string": return "f.ee.encodeString(c_UTF8, " + vname + ")" case "float32": return "f.ee.encodeFloat32(" + vname + ")" case "float64": return "f.ee.encodeFloat64(" + vname + ")" case "bool": return "f.ee.encodeBool(" + vname + ")" case "symbol": return "f.ee.encodeSymbol(" + vname + ")" default: return "f.e.encode(" + vname + ")" } } func DecCommandAsString(s string) string { switch s { case "uint": return "uint(f.dd.decodeUint(uintBitsize))" case "uint8": return "uint8(f.dd.decodeUint(8))" case "uint16": return "uint16(f.dd.decodeUint(16))" case "uint32": return "uint32(f.dd.decodeUint(32))" case "uint64": return "f.dd.decodeUint(64)" case "int": return "int(f.dd.decodeInt(intBitsize))" case "int8": return "int8(f.dd.decodeInt(8))" case "int16": return "int16(f.dd.decodeInt(16))" case "int32": return "int32(f.dd.decodeInt(32))" case "int64": return "f.dd.decodeInt(64)" case "string": return "f.dd.decodeString()" case "float32": return "float32(f.dd.decodeFloat(true))" case "float64": return "f.dd.decodeFloat(false)" case "bool": return "f.dd.decodeBool()" default: panic("unknown type for decode: " + s) } } func (x *genInfo) MethodName() string { var name []byte name = append(name, "fast"...) if x.Encode { name = append(name, "Enc"...) } else { name = append(name, "Dec"...) } if x.Slice { name = append(name, "Slice"...) } else { name = append(name, "Map"...) name = append(name, titleCaseName(x.MapKey)...) } name = append(name, titleCaseName(x.Elem)...) return string(name) } func titleCaseName(s string) string { switch s { case "interface{}": return "Intf" default: return strings.ToUpper(s[0:1]) + s[1:] } } type genTmpl struct { Values []genInfo } func main() { types := []string{ "interface{}", "string", "float32", "float64", "uint", "uint8", "uint16", "uint32", "uint64", "int", "int8", "int16", "int32", "int64", "bool", } var gt genTmpl for _, s := range types { if s != "uint8" { // do not generate fast path for slice of bytes. Treat specially already. gt.Values = append(gt.Values, genInfo{true, true, "", s}) gt.Values = append(gt.Values, genInfo{true, false, "", s}) } gt.Values = append(gt.Values, genInfo{false, true, s, "interface{}"}) gt.Values = append(gt.Values, genInfo{false, false, s, "interface{}"}) gt.Values = append(gt.Values, genInfo{false, true, s, "string"}) gt.Values = append(gt.Values, genInfo{false, false, s, "string"}) if s != "string" && s != "interface{}" { gt.Values = append(gt.Values, genInfo{false, true, s, s}) gt.Values = append(gt.Values, genInfo{false, false, s, s}) } } funcs := make(template.FuncMap) // funcs["haspfx"] = strings.HasPrefix funcs["encmd"] = EncCommandAsString funcs["decmd"] = DecCommandAsString t := template.New("") t = t.Funcs(funcs) t, err := t.Parse(tmplstr) if err != nil { panic(err) } var out bytes.Buffer err = t.Execute(&out, >) if err != nil { panic(err) } // os.Stdout.Write(out.Bytes()) bout, err := format.Source(out.Bytes()) if err != nil { panic(err) } os.Stdout.Write(bout) }