gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

fast-path.go.tmpl (17091B)


      1 // +build !notfastpath
      2 // +build !codec.notfastpath
      3 
      4 // Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
      5 // Use of this source code is governed by a MIT license found in the LICENSE file.
      6 
      7 // Code generated from fast-path.go.tmpl - DO NOT EDIT.
      8 
      9 package codec
     10 
     11 // Fast path functions try to create a fast path encode or decode implementation
     12 // for common maps and slices.
     13 //
     14 // We define the functions and register them in this single file
     15 // so as not to pollute the encode.go and decode.go, and create a dependency in there.
     16 // This file can be omitted without causing a build failure.
     17 //
     18 // The advantage of fast paths is:
     19 //	  - Many calls bypass reflection altogether
     20 // 
     21 // Currently support
     22 //	  - slice of all builtin types (numeric, bool, string, []byte)
     23 //    - maps of builtin types to builtin or interface{} type, EXCEPT FOR
     24 //      keys of type uintptr, int8/16/32, uint16/32, float32/64, bool, interface{}
     25 //      AND values of type type int8/16/32, uint16/32
     26 // This should provide adequate "typical" implementations.
     27 // 
     28 // Note that fast track decode functions must handle values for which an address cannot be obtained.
     29 // For example: 
     30 //	 m2 := map[string]int{}
     31 //	 p2 := []interface{}{m2}
     32 //	 // decoding into p2 will bomb if fast track functions do not treat like unaddressable.
     33 // 
     34 
     35 {{/*
     36 fastpathEncMapStringUint64R  (called by fastpath...switch)
     37 EncMapStringUint64V (called by codecgen)
     38 
     39 fastpathEncSliceBoolR: (called by fastpath...switch) (checks f.ti.mbs and calls one of them below)
     40 EncSliceBoolV  (also called by codecgen)
     41 EncAsMapSliceBoolV (delegate when mapbyslice=true)
     42 
     43 fastpathDecSliceIntfR (called by fastpath...switch) (calls Y or N below depending on if it can be updated)
     44 DecSliceIntfX  (called by codecgen) (calls Y below)
     45 DecSliceIntfY  (delegate when slice CAN be updated)
     46 DecSliceIntfN  (delegate when slice CANNOT be updated e.g. from array or non-addressable slice)
     47 
     48 fastpathDecMap...R (called by fastpath...switch) (calls L or X? below)
     49 DecMap...X  (called by codecgen)
     50 DecMap...L  (delegated to by both above)
     51 */ -}}
     52 
     53 import (
     54 	"reflect"
     55 	"sort"
     56 )
     57 
     58 const fastpathEnabled = true
     59 
     60 {{/*
     61 const fastpathMapBySliceErrMsg = "mapBySlice requires even slice length, but got %v"
     62 */ -}}
     63 
     64 type fastpathT struct {}
     65 
     66 var fastpathTV fastpathT
     67 
     68 type fastpathE struct {
     69 	{{/* rtid uintptr */ -}}
     70 	rt reflect.Type 
     71 	encfn func(*Encoder, *codecFnInfo, reflect.Value)
     72 	decfn func(*Decoder, *codecFnInfo, reflect.Value)
     73 }
     74 
     75 type fastpathA [{{ .FastpathLen }}]fastpathE
     76 type fastpathARtid [{{ .FastpathLen }}]uintptr
     77 
     78 var fastpathAv fastpathA
     79 var fastpathAvRtid fastpathARtid
     80 
     81 type fastpathAslice struct{}
     82 
     83 func (fastpathAslice) Len() int { return {{ .FastpathLen }} }
     84 func (fastpathAslice) Less(i, j int) bool {
     85 	return fastpathAvRtid[uint(i)] < fastpathAvRtid[uint(j)]
     86 }
     87 func (fastpathAslice) Swap(i, j int) {
     88 	fastpathAvRtid[uint(i)], fastpathAvRtid[uint(j)] = fastpathAvRtid[uint(j)], fastpathAvRtid[uint(i)]
     89 	fastpathAv[uint(i)], fastpathAv[uint(j)] = fastpathAv[uint(j)], fastpathAv[uint(i)]
     90 }
     91 
     92 func fastpathAvIndex(rtid uintptr) int {
     93 	// use binary search to grab the index (adapted from sort/search.go)
     94 	// Note: we use goto (instead of for loop) so this can be inlined.
     95  	// h, i, j := 0, 0, {{ .FastpathLen }}
     96 	var h, i uint
     97 	var j uint = {{ .FastpathLen }}
     98 LOOP:
     99 	if i < j {
    100 		h = (i + j) >> 1 // avoid overflow when computing h // h = i + (j-i)/2
    101 		if fastpathAvRtid[h] < rtid {
    102 			i = h + 1
    103 		} else {
    104 			j = h
    105 		}
    106 		goto LOOP
    107 	}
    108 	if i < {{ .FastpathLen }} && fastpathAvRtid[i] == rtid {
    109 		return int(i)
    110 	}
    111 	return -1
    112 }
    113 
    114 
    115 // due to possible initialization loop error, make fastpath in an init()
    116 func init() {
    117 	var i uint = 0
    118 	fn := func(v interface{},
    119 		fe func(*Encoder, *codecFnInfo, reflect.Value),
    120 		fd func(*Decoder, *codecFnInfo, reflect.Value)) {
    121 		xrt := reflect.TypeOf(v)
    122 		xptr := rt2id(xrt)
    123         fastpathAvRtid[i] = xptr
    124 		fastpathAv[i] = fastpathE{xrt, fe, fd}
    125 		i++
    126 	}
    127 	{{/* do not register []byte in fast-path */}}
    128 	{{range .Values}}{{if not .Primitive}}{{if not .MapKey -}}
    129 	fn([]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R)
    130 	{{end}}{{end}}{{end}}
    131 	
    132 	{{range .Values}}{{if not .Primitive}}{{if .MapKey -}}
    133 	fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R)
    134 	{{end}}{{end}}{{end}}
    135 	
    136 	sort.Sort(fastpathAslice{})
    137 }
    138 
    139 // -- encode
    140 
    141 // -- -- fast path type switch
    142 func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
    143 	switch v := iv.(type) {
    144 {{range .Values}}{{if not .Primitive}}{{if not .MapKey -}}
    145 	case []{{ .Elem }}:
    146 		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
    147 	case *[]{{ .Elem }}:
    148 		if *v == nil {
    149 			e.e.EncodeNil()
    150 		} else {
    151 			fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
    152 		}
    153 {{end}}{{end}}{{end -}}
    154 
    155 {{range .Values}}{{if not .Primitive}}{{if .MapKey -}}
    156 	case map[{{ .MapKey }}]{{ .Elem }}:
    157 		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
    158 	case *map[{{ .MapKey }}]{{ .Elem }}:
    159 		if *v == nil {
    160 			e.e.EncodeNil()
    161 		} else {
    162 			fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
    163 		}
    164 {{end}}{{end}}{{end -}}
    165 
    166 	default:
    167 		_ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
    168 		return false
    169 	}
    170 	return true
    171 }
    172 
    173 // -- -- fast path functions
    174 {{range .Values}}{{if not .Primitive}}{{if not .MapKey -}} 
    175 func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) {
    176 	var v  []{{ .Elem }}
    177 	if rv.Kind() == reflect.Array {
    178 		rvGetSlice4Array(rv, &v)
    179 	} else {
    180 		v = rv2i(rv).([]{{ .Elem }})
    181 	}
    182 	if f.ti.mbs {
    183 		fastpathTV.{{ .MethodNamePfx "EncAsMap" false }}V(v, e)
    184 	} else {
    185 		fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
    186 	}
    187 }
    188 func (fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, e *Encoder) {
    189 	{{/* if v == nil { e.e.EncodeNil(); return } */ -}}
    190 	{{ if eq .Elem "uint8" "byte" -}}
    191 	e.e.EncodeStringBytesRaw(v)
    192 	{{ else -}}
    193 	e.arrayStart(len(v))
    194 	for j := range v {
    195 		e.arrayElem()
    196 		{{ encmd .Elem "v[j]"}}
    197 	} 
    198 	e.arrayEnd()
    199 	{{ end -}}
    200 }
    201 func (fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, e *Encoder) {
    202 	{{/* if v == nil { e.e.EncodeNil() } else */ -}}
    203 	e.haltOnMbsOddLen(len(v))
    204 	{{/*
    205 	if len(v)&1 != 0 { // similar to &1==1 or %2 == 1
    206 		e.errorf(fastpathMapBySliceErrMsg, len(v))
    207 	}
    208 	*/ -}}
    209 	e.mapStart(len(v) >> 1) // e.mapStart(len(v) / 2)
    210 	for j := range v {
    211 		if j&1 == 0 { // if j%2 == 0 {
    212 			e.mapElemKey()
    213 		} else {
    214 			e.mapElemValue()
    215 		}
    216 		{{ encmd .Elem "v[j]"}}
    217 	}
    218 	e.mapEnd()
    219 }
    220 {{end}}{{end}}{{end -}}
    221 
    222 {{range .Values}}{{if not .Primitive}}{{if .MapKey -}}
    223 func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) {
    224 	fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), e)
    225 }
    226 func (fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, e *Encoder) {
    227 	{{/* if v == nil { e.e.EncodeNil(); return } */ -}}
    228 	e.mapStart(len(v))
    229 	if e.h.Canonical { {{/* need to figure out .NoCanonical */}}
    230 		{{if eq .MapKey "interface{}"}}{{/* out of band */ -}}
    231 		var mksv []byte = make([]byte, 0, len(v)*16) // temporary byte slice for the encoding
    232 		e2 := NewEncoderBytes(&mksv, e.hh)
    233 		v2 := make([]bytesIntf, len(v))
    234 		var i, l uint {{/* put loop variables outside. seems currently needed for better perf */}}
    235 		var vp *bytesIntf
    236 		for k2 := range v {
    237 			l = uint(len(mksv))
    238 			e2.MustEncode(k2)
    239 			vp = &v2[i]
    240 			vp.v = mksv[l:]
    241 			vp.i = k2 
    242 			i++
    243 		}
    244 		sort.Sort(bytesIntfSlice(v2))
    245 		for j := range v2 {
    246 			e.mapElemKey()
    247 			e.asis(v2[j].v)
    248 			e.mapElemValue()
    249 			e.encode(v[v2[j].i])
    250 		} {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v))
    251 		var i uint
    252 		for k := range v {
    253 			v2[i] = {{if eq $x .MapKey}}k{{else}}{{ $x }}(k){{end}}
    254 			i++
    255 		}
    256 		sort.Sort({{ sorttype .MapKey false}}(v2))
    257 		for _, k2 := range v2 {
    258 			e.mapElemKey()
    259 			{{if eq .MapKey "string"}} e.e.EncodeString(k2) {{else}}{{ $y := printf "%s(k2)" .MapKey }}{{if eq $x .MapKey }}{{ $y = "k2" }}{{end}}{{ encmd .MapKey $y }}{{end}}
    260 			e.mapElemValue()
    261 			{{ $y := printf "v[%s(k2)]" .MapKey }}{{if eq $x .MapKey }}{{ $y = "v[k2]" }}{{end}}{{ encmd .Elem $y }}
    262 		} {{end}}
    263 	} else { 
    264 		for k2, v2 := range v {
    265 			e.mapElemKey()
    266 			{{if eq .MapKey "string"}} e.e.EncodeString(k2) {{else}}{{ encmd .MapKey "k2"}}{{end}}
    267 			e.mapElemValue()
    268 			{{ encmd .Elem "v2"}}
    269 		}
    270 	}
    271 	e.mapEnd()
    272 }
    273 {{end}}{{end}}{{end -}}
    274 
    275 // -- decode
    276 
    277 // -- -- fast path type switch
    278 func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
    279 	var changed bool
    280 	var containerLen int
    281 	switch v := iv.(type) {
    282 {{range .Values}}{{if not .Primitive}}{{if not .MapKey -}}
    283 	case []{{ .Elem }}:
    284 		fastpathTV.{{ .MethodNamePfx "Dec" false }}N(v, d)
    285 	case *[]{{ .Elem }}:
    286 		var v2 []{{ .Elem }}
    287 		if v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}Y(*v, d); changed {
    288 			*v = v2
    289 		}
    290 {{end}}{{end}}{{end -}}
    291 {{range .Values}}{{if not .Primitive}}{{if .MapKey }}{{/*
    292 // maps only change if nil, and in that case, there's no point copying
    293 */ -}}
    294 	case map[{{ .MapKey }}]{{ .Elem }}:
    295 		containerLen = d.mapStart(d.d.ReadMapStart())
    296 		if containerLen != containerLenNil {
    297 			if containerLen != 0 {
    298 				fastpathTV.{{ .MethodNamePfx "Dec" false }}L(v, containerLen, d)
    299 			}
    300 			d.mapEnd()
    301 		}
    302 	case *map[{{ .MapKey }}]{{ .Elem }}:
    303 		{{/*
    304 		containerLen = d.mapStart(d.d.ReadMapStart())
    305 		if containerLen == 0 {
    306 			d.mapEnd()
    307 		} else if containerLen == containerLenNil {
    308 			*v = nil
    309 		} else {
    310 			if *v == nil {
    311 				*v = make(map[{{ .MapKey }}]{{ .Elem }}, decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }}))
    312 			}
    313 			fastpathTV.{{ .MethodNamePfx "Dec" false }}L(*v, containerLen, d)
    314 		}
    315 		// consider delegating fully to X - encoding *map is uncommon, so ok to pay small function call cost
    316 		*/ -}}
    317 		fastpathTV.{{ .MethodNamePfx "Dec" false }}X(v, d)
    318 {{end}}{{end}}{{end -}}
    319 	default:
    320 		_ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
    321 		return false
    322 	}
    323 	return true
    324 }
    325 
    326 func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool {
    327 	switch v := iv.(type) {
    328 {{range .Values}}{{if not .Primitive}}{{if not .MapKey -}}
    329 	case *[]{{ .Elem }}: 
    330 		*v = nil
    331 {{end}}{{end}}{{end}}
    332 {{range .Values}}{{if not .Primitive}}{{if .MapKey -}}
    333 	case *map[{{ .MapKey }}]{{ .Elem }}: 
    334 		*v = nil 
    335 {{end}}{{end}}{{end}}
    336 	default:
    337 		_ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
    338 		return false
    339 	}
    340 	return true
    341 }
    342 
    343 // -- -- fast path functions
    344 {{range .Values}}{{if not .Primitive}}{{if not .MapKey -}}
    345 {{/*
    346 Slices can change if they
    347 - did not come from an array
    348 - are addressable (from a ptr)
    349 - are settable (e.g. contained in an interface{})
    350 */}}
    351 func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
    352 	{{/*
    353     // seqTypeArray=true means that we are not getting a pointer, so no need to check that.
    354     if f.seq != seqTypeArray && rv.Kind() == reflect.Ptr {
    355     */ -}}
    356 	var v  []{{ .Elem }}
    357 	switch rv.Kind() {
    358 	case reflect.Ptr:
    359 		vp := rv2i(rv).(*[]{{ .Elem }})
    360 		var changed bool
    361 		if v, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}Y(*vp, d); changed {
    362 			*vp = v
    363 		}
    364 	case reflect.Array:
    365 		rvGetSlice4Array(rv, &v)
    366 		fastpathTV.{{ .MethodNamePfx "Dec" false }}N(v, d)
    367 	default:
    368 		fastpathTV.{{ .MethodNamePfx "Dec" false }}N(rv2i(rv).([]{{ .Elem }}), d)
    369 	}
    370 }
    371 func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, d *Decoder) {
    372 	if v, changed := f.{{ .MethodNamePfx "Dec" false }}Y(*vp, d); changed { *vp = v }
    373 }
    374 func (fastpathT) {{ .MethodNamePfx "Dec" false }}Y(v []{{ .Elem }}, d *Decoder) (v2 []{{ .Elem }}, changed bool) {
    375 	{{ if eq .Elem "uint8" "byte" -}}
    376 	switch d.d.ContainerType() {
    377 	case valueTypeNil, valueTypeMap:
    378 		break
    379 	default:
    380 		v2 = d.decodeBytesInto(v[:len(v):len(v)])
    381 		changed = !(len(v2) > 0 && len(v2) == len(v) && &v2[0] == &v[0]) // not same slice
    382 		return
    383 	}
    384 	{{ end -}}
    385 	slh, containerLenS := d.decSliceHelperStart()
    386 	if slh.IsNil {
    387 		if v == nil { return }
    388 		return nil, true
    389 	}
    390 	if containerLenS == 0 {
    391 		if v == nil { v = []{{ .Elem }}{} } else if len(v) != 0 { v = v[:0] }
    392 		slh.End()
    393 		return v, true
    394 	}
    395 	hasLen := containerLenS > 0
    396 	var xlen int 
    397 	if hasLen {
    398 		if containerLenS > cap(v) {
    399 			xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
    400 			if xlen <= cap(v) {
    401 				v = v[:uint(xlen)]
    402 			} else {
    403 				v = make([]{{ .Elem }}, uint(xlen))
    404 			}
    405 			changed = true 
    406 		} else if containerLenS != len(v) {
    407 			v = v[:containerLenS]
    408 			changed = true
    409 		}
    410 	}
    411 	var j int
    412     for j = 0; d.containerNext(j, containerLenS, hasLen); j++ {
    413 		if j == 0 && len(v) == 0 { // means hasLen == false
    414 			xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }}) {{/* xlen = decDefSliceCap */}}
    415 			v = make([]{{ .Elem }}, uint(xlen))
    416 			changed = true
    417 		}
    418 		{{/* // if indefinite, etc, then expand the slice if necessary */ -}}
    419 		if j >= len(v) {
    420 			v = append(v, {{ zerocmd .Elem }})
    421 			changed = true
    422 		} 
    423 		slh.ElemContainerState(j)
    424 		{{ if eq .Elem "interface{}" }}d.decode(&v[uint(j)]){{ else }}v[uint(j)] = {{ decmd .Elem false }}{{ end }}
    425 	}
    426 	if j < len(v) {
    427 		v = v[:uint(j)]
    428 		changed = true
    429 	} else if j == 0 && v == nil {
    430 		v = []{{ .Elem }}{}
    431 		changed = true
    432 	}
    433 	slh.End()
    434 	return v, changed
    435 }
    436 func (fastpathT) {{ .MethodNamePfx "Dec" false }}N(v []{{ .Elem }}, d *Decoder) {
    437 	{{ if eq .Elem "uint8" "byte" -}}
    438 	switch d.d.ContainerType() {
    439 	case valueTypeNil, valueTypeMap:
    440 		break
    441 	default:
    442 		v2 := d.decodeBytesInto(v[:len(v):len(v)])
    443 		if !(len(v2) > 0 && len(v2) == len(v) && &v2[0] == &v[0]) { // not same slice
    444 			copy(v, v2)
    445 		}
    446 		return
    447 	}
    448 	{{ end -}}
    449 	slh, containerLenS := d.decSliceHelperStart()
    450 	if slh.IsNil {
    451 		return
    452 	}
    453 	if containerLenS == 0 {
    454 		slh.End()
    455 		return
    456 	}
    457 	hasLen := containerLenS > 0
    458     for j := 0; d.containerNext(j, containerLenS, hasLen); j++ {
    459 		{{/* // if indefinite, etc, then expand the slice if necessary */ -}}
    460 		if j >= len(v) {
    461 			slh.arrayCannotExpand(hasLen, len(v), j, containerLenS)
    462 			return
    463 		} 
    464 		slh.ElemContainerState(j)
    465 		{{ if eq .Elem "interface{}" -}}
    466 		d.decode(&v[uint(j)])
    467 		{{- else -}}
    468 		v[uint(j)] = {{ decmd .Elem false }}
    469 		{{- end }}
    470 	}
    471 	slh.End()
    472 }
    473 {{end}}{{end}}{{end -}}
    474 
    475 {{range .Values}}{{if not .Primitive}}{{if .MapKey -}}
    476 {{/*
    477 Maps can change if they are
    478 - addressable (from a ptr)
    479 - settable (e.g. contained in an interface{})
    480 
    481 Also, these methods are called by decodeValue directly, after handling a TryNil.
    482 Consequently, there's no need to check for containerLenNil here.
    483 */ -}}
    484 func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
    485 	containerLen := d.mapStart(d.d.ReadMapStart())
    486     {{/*
    487 	if containerLen == containerLenNil {
    488 		if rv.Kind() == reflect.Ptr {
    489 			*(rv2i(rv).(*map[{{ .MapKey }}]{{ .Elem }})) = nil
    490 		}
    491         return
    492 	}
    493     */ -}}
    494 	if rv.Kind() == reflect.Ptr {
    495 		vp, _ := rv2i(rv).(*map[{{ .MapKey }}]{{ .Elem }})
    496 		if *vp == nil {
    497 			*vp = make(map[{{ .MapKey }}]{{ .Elem }}, decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }}))
    498 		}
    499 		if containerLen != 0 {
    500 			fastpathTV.{{ .MethodNamePfx "Dec" false }}L(*vp, containerLen, d)
    501 		}
    502 	} else if containerLen != 0 {
    503 		fastpathTV.{{ .MethodNamePfx "Dec" false }}L(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), containerLen, d)
    504 	}
    505 	d.mapEnd()
    506 }
    507 func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .Elem }}, d *Decoder) {
    508 	containerLen := d.mapStart(d.d.ReadMapStart())
    509 	if containerLen == containerLenNil {
    510 		*vp = nil
    511 	} else {
    512 		if *vp == nil {
    513 			*vp = make(map[{{ .MapKey }}]{{ .Elem }}, decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }}))
    514 		}
    515 		if containerLen != 0 {
    516 			f.{{ .MethodNamePfx "Dec" false }}L(*vp, containerLen, d)
    517 		}
    518 		d.mapEnd()
    519 	}
    520 }
    521 func (fastpathT) {{ .MethodNamePfx "Dec" false }}L(v map[{{ .MapKey }}]{{ .Elem }}, containerLen int, d *Decoder) {
    522 	{{/* No need to check if containerLen == containerLenNil, as that is checked by R and L above  */ -}}
    523 	if v == nil {
    524 		d.errorf("cannot decode into nil map[{{ .MapKey }}]{{ .Elem }} given stream length: %v", containerLen)
    525         {{/* d.swallowMapContents(containerLen) */ -}}
    526 		return
    527 	}
    528 	{{if eq .Elem "interface{}" }}mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset
    529     {{else if eq .Elem "bytes" "[]byte" }}mapGet := v != nil && !d.h.MapValueReset
    530     {{end -}}
    531     var mk {{ .MapKey }}
    532 	var mv {{ .Elem }}
    533 	hasLen := containerLen > 0
    534     for j := 0; d.containerNext(j, containerLen, hasLen); j++ {
    535 		d.mapElemKey()
    536 		{{ if eq .MapKey "interface{}" }}mk = nil 
    537 		d.decode(&mk)
    538 		if bv, bok := mk.([]byte); bok {
    539 			mk = d.stringZC(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
    540 		}{{ else }}mk = {{ decmd .MapKey true }}{{ end }}
    541 		d.mapElemValue()
    542 		{{ if eq .Elem "interface{}" "[]byte" "bytes" -}}
    543 		if mapGet { mv = v[mk] } else { mv = nil }
    544 		{{ end -}}
    545 		{{ if eq .Elem "interface{}" -}}
    546 		d.decode(&mv)
    547 		{{ else if eq .Elem "[]byte" "bytes" -}}
    548 		mv = d.decodeBytesInto(mv)
    549 		{{ else -}}
    550 		mv = {{ decmd .Elem false }}
    551 		{{ end -}}
    552 		v[mk] = mv
    553 	}
    554 }
    555 {{end}}{{end}}{{end}}