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