fast-path.go.tmpl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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. import (
  30. "reflect"
  31. "sort"
  32. )
  33. const fastpathEnabled = true
  34. const fastpathMapBySliceErrMsg = "mapBySlice requires even slice length, but got %v"
  35. type fastpathT struct {}
  36. var fastpathTV fastpathT
  37. type fastpathE struct {
  38. rtid uintptr
  39. rt reflect.Type
  40. encfn func(*Encoder, *codecFnInfo, reflect.Value)
  41. decfn func(*Decoder, *codecFnInfo, reflect.Value)
  42. }
  43. type fastpathA [{{ .FastpathLen }}]fastpathE
  44. func (x *fastpathA) index(rtid uintptr) int {
  45. // use binary search to grab the index (adapted from sort/search.go)
  46. // Note: we use goto (instead of for loop) so this can be inlined.
  47. // h, i, j := 0, 0, len(x)
  48. var h, i uint
  49. var j = uint(len(x))
  50. LOOP:
  51. if i < j {
  52. h = i + (j-i)/2
  53. if x[h].rtid < rtid {
  54. i = h + 1
  55. } else {
  56. j = h
  57. }
  58. goto LOOP
  59. }
  60. if i < uint(len(x)) && x[i].rtid == rtid {
  61. return int(i)
  62. }
  63. return -1
  64. }
  65. type fastpathAslice []fastpathE
  66. func (x fastpathAslice) Len() int { return len(x) }
  67. func (x fastpathAslice) Less(i, j int) bool { return x[uint(i)].rtid < x[uint(j)].rtid }
  68. func (x fastpathAslice) Swap(i, j int) { x[uint(i)], x[uint(j)] = x[uint(j)], x[uint(i)] }
  69. var fastpathAV fastpathA
  70. // due to possible initialization loop error, make fastpath in an init()
  71. func init() {
  72. var i uint = 0
  73. fn := func(v interface{},
  74. fe func(*Encoder, *codecFnInfo, reflect.Value),
  75. fd func(*Decoder, *codecFnInfo, reflect.Value)) {
  76. xrt := reflect.TypeOf(v)
  77. xptr := rt2id(xrt)
  78. fastpathAV[i] = fastpathE{xptr, xrt, fe, fd}
  79. i++
  80. }
  81. {{/* do not register []uint8 in fast-path */}}
  82. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}}
  83. fn([]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}{{end}}
  84. {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
  85. fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (*Encoder).{{ .MethodNamePfx "fastpathEnc" false }}R, (*Decoder).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
  86. sort.Sort(fastpathAslice(fastpathAV[:]))
  87. }
  88. // -- encode
  89. // -- -- fast path type switch
  90. func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
  91. switch v := iv.(type) {
  92. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}}
  93. case []{{ .Elem }}:
  94. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
  95. case *[]{{ .Elem }}:
  96. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e){{/*
  97. */}}{{end}}{{end}}{{end}}{{end}}
  98. {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
  99. case map[{{ .MapKey }}]{{ .Elem }}:
  100. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
  101. case *map[{{ .MapKey }}]{{ .Elem }}:
  102. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e){{/*
  103. */}}{{end}}{{end}}{{end}}
  104. default:
  105. _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
  106. return false
  107. }
  108. return true
  109. }
  110. {{/*
  111. **** removing this block, as they are never called directly ****
  112. **** removing this block, as they are never called directly ****
  113. func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
  114. switch v := iv.(type) {
  115. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
  116. case []{{ .Elem }}:
  117. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
  118. case *[]{{ .Elem }}:
  119. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
  120. {{end}}{{end}}{{end}}
  121. default:
  122. _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
  123. return false
  124. }
  125. return true
  126. }
  127. func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
  128. switch v := iv.(type) {
  129. {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
  130. case map[{{ .MapKey }}]{{ .Elem }}:
  131. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, e)
  132. case *map[{{ .MapKey }}]{{ .Elem }}:
  133. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, e)
  134. {{end}}{{end}}{{end}}
  135. default:
  136. _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
  137. return false
  138. }
  139. return true
  140. }
  141. **** removing this block, as they are never called directly ****
  142. **** removing this block, as they are never called directly ****
  143. */}}
  144. // -- -- fast path functions
  145. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
  146. func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) {
  147. if f.ti.mbs {
  148. fastpathTV.{{ .MethodNamePfx "EncAsMap" false }}V(rv2i(rv).([]{{ .Elem }}), e)
  149. } else {
  150. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv2i(rv).([]{{ .Elem }}), e)
  151. }
  152. }
  153. func (fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, e *Encoder) {
  154. if v == nil {
  155. e.e.EncodeNil()
  156. return
  157. }
  158. e.arrayStart(len(v))
  159. for j := range v {
  160. e.arrayElem()
  161. {{ encmd .Elem "v[j]"}}
  162. }
  163. e.arrayEnd()
  164. }
  165. func (fastpathT) {{ .MethodNamePfx "EncAsMap" false }}V(v []{{ .Elem }}, e *Encoder) {
  166. if v == nil {
  167. e.e.EncodeNil()
  168. } else if len(v)%2 == 1 {
  169. e.errorf(fastpathMapBySliceErrMsg, len(v))
  170. } else {
  171. e.mapStart(len(v) / 2)
  172. for j := range v {
  173. if j%2 == 0 {
  174. e.mapElemKey()
  175. } else {
  176. e.mapElemValue()
  177. }
  178. {{ encmd .Elem "v[j]"}}
  179. }
  180. e.mapEnd()
  181. }
  182. }
  183. {{end}}{{end}}{{end}}
  184. {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
  185. func (e *Encoder) {{ .MethodNamePfx "fastpathEnc" false }}R(f *codecFnInfo, rv reflect.Value) {
  186. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), e)
  187. }
  188. func (fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, e *Encoder) {
  189. if v == nil { e.e.EncodeNil(); return }
  190. e.mapStart(len(v))
  191. if e.h.Canonical { {{/* need to figure out .NoCanonical */}}
  192. {{if eq .MapKey "interface{}"}}{{/* out of band */ -}}
  193. var mksv []byte = make([]byte, 0, len(v)*16) // temporary byte slice for the encoding
  194. e2 := NewEncoderBytes(&mksv, e.hh)
  195. v2 := make([]bytesIntf, len(v))
  196. var i, l uint
  197. var vp *bytesIntf {{/* put loop variables outside. seems currently needed for better perf */}}
  198. for k2 := range v {
  199. l = uint(len(mksv))
  200. e2.MustEncode(k2)
  201. vp = &v2[i]
  202. vp.v = mksv[l:]
  203. vp.i = k2
  204. i++
  205. }
  206. sort.Sort(bytesIntfSlice(v2))
  207. for j := range v2 {
  208. e.mapElemKey()
  209. e.asis(v2[j].v)
  210. e.mapElemValue()
  211. e.encode(v[v2[j].i])
  212. } {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v))
  213. var i uint
  214. for k := range v {
  215. v2[i] = {{if eq $x .MapKey}}k{{else}}{{ $x }}(k){{end}}
  216. i++
  217. }
  218. sort.Sort({{ sorttype .MapKey false}}(v2))
  219. for _, k2 := range v2 {
  220. e.mapElemKey()
  221. {{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}}
  222. e.mapElemValue()
  223. {{ $y := printf "v[%s(k2)]" .MapKey }}{{if eq $x .MapKey }}{{ $y = "v[k2]" }}{{end}}{{ encmd .Elem $y }}
  224. } {{end}}
  225. } else {
  226. for k2, v2 := range v {
  227. e.mapElemKey()
  228. {{if eq .MapKey "string"}} if e.h.StringToRaw {e.e.EncodeStringBytesRaw(bytesView(k2))} else {e.e.EncodeStringEnc(cUTF8, k2)} {{else}}{{ encmd .MapKey "k2"}}{{end}}
  229. e.mapElemValue()
  230. {{ encmd .Elem "v2"}}
  231. }
  232. }
  233. e.mapEnd()
  234. }
  235. {{end}}{{end}}{{end}}
  236. // -- decode
  237. // -- -- fast path type switch
  238. func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
  239. var changed bool
  240. switch v := iv.(type) {
  241. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}{{if ne .Elem "uint8"}}
  242. case []{{ .Elem }}:
  243. var v2 []{{ .Elem }}
  244. v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, false, d)
  245. if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) {
  246. copy(v, v2)
  247. }
  248. case *[]{{ .Elem }}:
  249. var v2 []{{ .Elem }}
  250. v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d)
  251. if changed {
  252. *v = v2
  253. }{{/*
  254. */}}{{end}}{{end}}{{end}}{{end}}
  255. {{range .Values}}{{if not .Primitive}}{{if .MapKey }}{{/*
  256. // maps only change if nil, and in that case, there's no point copying
  257. */}}
  258. case map[{{ .MapKey }}]{{ .Elem }}:
  259. fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, false, d)
  260. case *map[{{ .MapKey }}]{{ .Elem }}:
  261. var v2 map[{{ .MapKey }}]{{ .Elem }}
  262. v2, changed = fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, true, d)
  263. if changed {
  264. *v = v2
  265. }{{/*
  266. */}}{{end}}{{end}}{{end}}
  267. default:
  268. _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
  269. return false
  270. }
  271. return true
  272. }
  273. func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool {
  274. switch v := iv.(type) {
  275. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
  276. case *[]{{ .Elem }}:
  277. *v = nil {{/*
  278. */}}{{end}}{{end}}{{end}}
  279. {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
  280. case *map[{{ .MapKey }}]{{ .Elem }}:
  281. *v = nil {{/*
  282. */}}{{end}}{{end}}{{end}}
  283. default:
  284. _ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
  285. return false
  286. }
  287. return true
  288. }
  289. // -- -- fast path functions
  290. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
  291. {{/*
  292. Slices can change if they
  293. - did not come from an array
  294. - are addressable (from a ptr)
  295. - are settable (e.g. contained in an interface{})
  296. */}}
  297. func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
  298. if array := f.seq == seqTypeArray; !array && rv.Kind() == reflect.Ptr {
  299. vp := rv2i(rv).(*[]{{ .Elem }})
  300. if v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, !array, d); changed { *vp = v }
  301. } else {
  302. v := rv2i(rv).([]{{ .Elem }})
  303. v2, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, !array, d)
  304. if changed && len(v) > 0 && len(v2) > 0 && !(len(v2) == len(v) && &v2[0] == &v[0]) {
  305. copy(v, v2)
  306. }
  307. }
  308. }
  309. func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, d *Decoder) {
  310. if v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed { *vp = v }
  311. }
  312. func (fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, canChange bool, d *Decoder) (_ []{{ .Elem }}, changed bool) {
  313. {{/* dd := d.d
  314. // if d.d.isContainerType(valueTypeNil) { d.d.TryDecodeAsNil() }
  315. */ -}}
  316. slh, containerLenS := d.decSliceHelperStart()
  317. if containerLenS == 0 {
  318. if canChange {
  319. if v == nil { v = []{{ .Elem }}{} } else if len(v) != 0 { v = v[:0] }
  320. changed = true
  321. }
  322. slh.End()
  323. return v, changed
  324. }
  325. hasLen := containerLenS > 0
  326. var xlen int
  327. if hasLen && canChange {
  328. if containerLenS > cap(v) {
  329. xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
  330. if xlen <= cap(v) {
  331. v = v[:uint(xlen)]
  332. } else {
  333. v = make([]{{ .Elem }}, uint(xlen))
  334. }
  335. changed = true
  336. } else if containerLenS != len(v) {
  337. v = v[:containerLenS]
  338. changed = true
  339. }
  340. }
  341. var j int
  342. for j = 0; (hasLen && j < containerLenS) || !(hasLen || d.d.CheckBreak()); j++ {
  343. if j == 0 && len(v) == 0 && canChange {
  344. if hasLen {
  345. xlen = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
  346. } else {
  347. xlen = 8
  348. }
  349. v = make([]{{ .Elem }}, uint(xlen))
  350. changed = true
  351. }
  352. {{/* // if indefinite, etc, then expand the slice if necessary */ -}}
  353. var decodeIntoBlank bool
  354. if j >= len(v) {
  355. if canChange {
  356. v = append(v, {{ zerocmd .Elem }})
  357. changed = true
  358. } else {
  359. d.arrayCannotExpand(len(v), j+1)
  360. decodeIntoBlank = true
  361. }
  362. }
  363. slh.ElemContainerState(j)
  364. if decodeIntoBlank {
  365. d.swallow()
  366. } else if d.d.TryDecodeAsNil() {
  367. v[uint(j)] = {{ zerocmd .Elem }}
  368. } else {
  369. {{ if eq .Elem "interface{}" }}d.decode(&v[uint(j)]){{ else }}v[uint(j)] = {{ decmd .Elem }}{{ end }}
  370. }
  371. }
  372. if canChange {
  373. if j < len(v) {
  374. v = v[:uint(j)]
  375. changed = true
  376. } else if j == 0 && v == nil {
  377. v = make([]{{ .Elem }}, 0)
  378. changed = true
  379. }
  380. }
  381. slh.End()
  382. return v, changed
  383. }
  384. {{end}}{{end}}{{end}}
  385. {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
  386. {{/*
  387. Maps can change if they are
  388. - addressable (from a ptr)
  389. - settable (e.g. contained in an interface{})
  390. */}}
  391. func (d *Decoder) {{ .MethodNamePfx "fastpathDec" false }}R(f *codecFnInfo, rv reflect.Value) {
  392. if rv.Kind() == reflect.Ptr {
  393. vp := rv2i(rv).(*map[{{ .MapKey }}]{{ .Elem }})
  394. if v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed { *vp = v }
  395. } else {
  396. fastpathTV.{{ .MethodNamePfx "Dec" false }}V(rv2i(rv).(map[{{ .MapKey }}]{{ .Elem }}), false, d)
  397. }
  398. }
  399. func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .Elem }}, d *Decoder) {
  400. if v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, true, d); changed { *vp = v }
  401. }
  402. func (fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, canChange bool,
  403. d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) {
  404. {{/*
  405. // if d.d.isContainerType(valueTypeNil) {d.d.TryDecodeAsNil()
  406. */ -}}
  407. containerLen := d.mapStart()
  408. if canChange && v == nil {
  409. v = make(map[{{ .MapKey }}]{{ .Elem }}, decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }}))
  410. changed = true
  411. }
  412. if containerLen == 0 {
  413. d.mapEnd()
  414. return v, changed
  415. }
  416. {{if eq .Elem "interface{}" }}mapGet := v != nil && !d.h.MapValueReset && !d.h.InterfaceReset
  417. {{else if eq .Elem "bytes" "[]byte" }}mapGet := v != nil && !d.h.MapValueReset
  418. {{end -}}
  419. var mk {{ .MapKey }}
  420. var mv {{ .Elem }}
  421. hasLen := containerLen > 0
  422. for j := 0; (hasLen && j < containerLen) || !(hasLen || d.d.CheckBreak()); j++ {
  423. d.mapElemKey()
  424. {{ if eq .MapKey "interface{}" }}mk = nil
  425. d.decode(&mk)
  426. if bv, bok := mk.([]byte); bok {
  427. mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
  428. }{{ else }}mk = {{ decmd .MapKey }}{{ end }}
  429. d.mapElemValue()
  430. if d.d.TryDecodeAsNil() {
  431. if v == nil {} else if d.h.DeleteOnNilMapValue { delete(v, mk) } else { v[mk] = {{ zerocmd .Elem }} }
  432. continue
  433. }
  434. {{ if eq .Elem "interface{}" "[]byte" "bytes" -}}
  435. if mapGet { mv = v[mk] } else { mv = nil }
  436. {{ end -}}
  437. {{ if eq .Elem "interface{}" -}}
  438. d.decode(&mv)
  439. {{ else if eq .Elem "[]byte" "bytes" -}}
  440. mv = d.d.DecodeBytes(mv, false)
  441. {{ else -}}
  442. mv = {{ decmd .Elem }}
  443. {{ end -}}
  444. if v != nil { v[mk] = mv }
  445. }
  446. d.mapEnd()
  447. return v, changed
  448. }
  449. {{end}}{{end}}{{end}}