fast-path.go.tmpl 15 KB

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