forked from mirror/ledisdb
443 lines
12 KiB
Cheetah
443 lines
12 KiB
Cheetah
// //+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}}
|