fast-path.go.tmpl 17 KB

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