fast-path.go.tmpl 14 KB

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