| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- //+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)
- }
|