fast-path.go.tmpl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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. // - symetrical 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 fastpathCheckNilFalse = false // for reflect
  36. const fastpathCheckNilTrue = true // for type switch
  37. type fastpathT struct {}
  38. var fastpathTV fastpathT
  39. type fastpathE struct {
  40. rtid uintptr
  41. rt reflect.Type
  42. encfn func(*encFnInfo, reflect.Value)
  43. decfn func(*decFnInfo, reflect.Value)
  44. }
  45. type fastpathA [{{ .FastpathLen }}]fastpathE
  46. func (x *fastpathA) index(rtid uintptr) int {
  47. // use binary search to grab the index (adapted from sort/search.go)
  48. h, i, j := 0, 0, {{ .FastpathLen }} // len(x)
  49. for i < j {
  50. h = i + (j-i)/2
  51. if x[h].rtid < rtid {
  52. i = h + 1
  53. } else {
  54. j = h
  55. }
  56. }
  57. if i < {{ .FastpathLen }} && x[i].rtid == rtid {
  58. return i
  59. }
  60. return -1
  61. }
  62. type fastpathAslice []fastpathE
  63. func (x fastpathAslice) Len() int { return len(x) }
  64. func (x fastpathAslice) Less(i, j int) bool { return x[i].rtid < x[j].rtid }
  65. func (x fastpathAslice) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
  66. var fastpathAV fastpathA
  67. // due to possible initialization loop error, make fastpath in an init()
  68. func init() {
  69. if !fastpathEnabled {
  70. return
  71. }
  72. i := 0
  73. fn := func(v interface{}, fe func(*encFnInfo, reflect.Value), fd func(*decFnInfo, reflect.Value)) (f fastpathE) {
  74. xrt := reflect.TypeOf(v)
  75. xptr := reflect.ValueOf(xrt).Pointer()
  76. fastpathAV[i] = fastpathE{xptr, xrt, fe, fd}
  77. i++
  78. return
  79. }
  80. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
  81. fn([]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (*decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
  82. {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
  83. fn(map[{{ .MapKey }}]{{ .Elem }}(nil), (*encFnInfo).{{ .MethodNamePfx "fastpathEnc" false }}R, (*decFnInfo).{{ .MethodNamePfx "fastpathDec" false }}R){{end}}{{end}}{{end}}
  84. sort.Sort(fastpathAslice(fastpathAV[:]))
  85. }
  86. // -- encode
  87. // -- -- fast path type switch
  88. func fastpathEncodeTypeSwitch(iv interface{}, e *Encoder) bool {
  89. if !fastpathEnabled {
  90. return false
  91. }
  92. switch v := iv.(type) {
  93. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
  94. case []{{ .Elem }}:{{else}}
  95. case map[{{ .MapKey }}]{{ .Elem }}:{{end}}
  96. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e){{if not .MapKey }}
  97. case *[]{{ .Elem }}:{{else}}
  98. case *map[{{ .MapKey }}]{{ .Elem }}:{{end}}
  99. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
  100. {{end}}{{end}}
  101. default:
  102. _ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
  103. return false
  104. }
  105. return true
  106. }
  107. func fastpathEncodeTypeSwitchSlice(iv interface{}, e *Encoder) bool {
  108. if !fastpathEnabled {
  109. return false
  110. }
  111. switch v := iv.(type) {
  112. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
  113. case []{{ .Elem }}:
  114. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(v, fastpathCheckNilTrue, e)
  115. case *[]{{ .Elem }}:
  116. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
  117. {{end}}{{end}}{{end}}
  118. default:
  119. _ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
  120. return false
  121. }
  122. return true
  123. }
  124. func fastpathEncodeTypeSwitchMap(iv interface{}, e *Encoder) bool {
  125. if !fastpathEnabled {
  126. return false
  127. }
  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, fastpathCheckNilTrue, e)
  132. case *map[{{ .MapKey }}]{{ .Elem }}:
  133. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(*v, fastpathCheckNilTrue, e)
  134. {{end}}{{end}}{{end}}
  135. default:
  136. _ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
  137. return false
  138. }
  139. return true
  140. }
  141. // -- -- fast path functions
  142. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
  143. func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) {
  144. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().([]{{ .Elem }}), fastpathCheckNilFalse, f.e)
  145. }
  146. func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v []{{ .Elem }}, checkNil bool, e *Encoder) {
  147. ee := e.e
  148. cr := e.cr
  149. if checkNil && v == nil {
  150. ee.EncodeNil()
  151. return
  152. }
  153. ee.EncodeArrayStart(len(v))
  154. for _, v2 := range v {
  155. if cr != nil { cr.sendContainerState(containerArrayElem) }
  156. {{ encmd .Elem "v2"}}
  157. }
  158. if cr != nil { cr.sendContainerState(containerArrayEnd) }{{/* ee.EncodeEnd() */}}
  159. }
  160. {{end}}{{end}}{{end}}
  161. {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
  162. func (f *encFnInfo) {{ .MethodNamePfx "fastpathEnc" false }}R(rv reflect.Value) {
  163. fastpathTV.{{ .MethodNamePfx "Enc" false }}V(rv.Interface().(map[{{ .MapKey }}]{{ .Elem }}), fastpathCheckNilFalse, f.e)
  164. }
  165. func (_ fastpathT) {{ .MethodNamePfx "Enc" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, e *Encoder) {
  166. ee := e.e
  167. cr := e.cr
  168. if checkNil && v == nil {
  169. ee.EncodeNil()
  170. return
  171. }
  172. ee.EncodeMapStart(len(v))
  173. {{if eq .MapKey "string"}}asSymbols := e.h.AsSymbols&AsSymbolMapStringKeysFlag != 0
  174. {{end}}if e.h.Canonical {
  175. {{if eq .MapKey "interface{}"}}{{/* out of band
  176. */}}var mksv []byte = make([]byte, 0, len(v)*16) // temporary byte slice for the encoding
  177. e2 := NewEncoderBytes(&mksv, e.hh)
  178. v2 := make([]bytesI, len(v))
  179. var i, l int
  180. var vp *bytesI {{/* put loop variables outside. seems currently needed for better perf */}}
  181. for k2, _ := range v {
  182. l = len(mksv)
  183. e2.MustEncode(k2)
  184. vp = &v2[i]
  185. vp.v = mksv[l:]
  186. vp.i = k2
  187. i++
  188. }
  189. sort.Sort(bytesISlice(v2))
  190. for j := range v2 {
  191. if cr != nil { cr.sendContainerState(containerMapKey) }
  192. e.asis(v2[j].v)
  193. if cr != nil { cr.sendContainerState(containerMapValue) }
  194. e.encode(v[v2[j].i])
  195. } {{else}}{{ $x := sorttype .MapKey true}}v2 := make([]{{ $x }}, len(v))
  196. var i int
  197. for k, _ := range v {
  198. v2[i] = {{ $x }}(k)
  199. i++
  200. }
  201. sort.Sort({{ sorttype .MapKey false}}(v2))
  202. for _, k2 := range v2 {
  203. if cr != nil { cr.sendContainerState(containerMapKey) }
  204. {{if eq .MapKey "string"}}if asSymbols {
  205. ee.EncodeSymbol(k2)
  206. } else {
  207. ee.EncodeString(c_UTF8, k2)
  208. }{{else}}{{ $y := printf "%s(k2)" .MapKey }}{{ encmd .MapKey $y }}{{end}}
  209. if cr != nil { cr.sendContainerState(containerMapValue) }
  210. {{ $y := printf "v[%s(k2)]" .MapKey }}{{ encmd .Elem $y }}
  211. } {{end}}
  212. } else {
  213. for k2, v2 := range v {
  214. if cr != nil { cr.sendContainerState(containerMapKey) }
  215. {{if eq .MapKey "string"}}if asSymbols {
  216. ee.EncodeSymbol(k2)
  217. } else {
  218. ee.EncodeString(c_UTF8, k2)
  219. }{{else}}{{ encmd .MapKey "k2"}}{{end}}
  220. if cr != nil { cr.sendContainerState(containerMapValue) }
  221. {{ encmd .Elem "v2"}}
  222. }
  223. }
  224. if cr != nil { cr.sendContainerState(containerMapEnd) }{{/* ee.EncodeEnd() */}}
  225. }
  226. {{end}}{{end}}{{end}}
  227. // -- decode
  228. // -- -- fast path type switch
  229. func fastpathDecodeTypeSwitch(iv interface{}, d *Decoder) bool {
  230. if !fastpathEnabled {
  231. return false
  232. }
  233. switch v := iv.(type) {
  234. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
  235. case []{{ .Elem }}:{{else}}
  236. case map[{{ .MapKey }}]{{ .Elem }}:{{end}}
  237. fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, d){{if not .MapKey }}
  238. case *[]{{ .Elem }}:{{else}}
  239. case *map[{{ .MapKey }}]{{ .Elem }}:{{end}}
  240. v2, changed2 := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*v, fastpathCheckNilFalse, true, d)
  241. if changed2 {
  242. *v = v2
  243. }
  244. {{end}}{{end}}
  245. default:
  246. _ = v // TODO: workaround https://github.com/golang/go/issues/12927 (remove after go 1.6 release)
  247. return false
  248. }
  249. return true
  250. }
  251. // -- -- fast path functions
  252. {{range .Values}}{{if not .Primitive}}{{if not .MapKey }}
  253. {{/*
  254. Slices can change if they
  255. - did not come from an array
  256. - are addressable (from a ptr)
  257. - are settable (e.g. contained in an interface{})
  258. */}}
  259. func (f *decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) {
  260. array := f.seq == seqTypeArray
  261. if !array && rv.CanAddr() { {{/* // CanSet => CanAddr + Exported */}}
  262. vp := rv.Addr().Interface().(*[]{{ .Elem }})
  263. v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, !array, f.d)
  264. if changed {
  265. *vp = v
  266. }
  267. } else {
  268. v := rv.Interface().([]{{ .Elem }})
  269. fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, f.d)
  270. }
  271. }
  272. func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *[]{{ .Elem }}, checkNil bool, d *Decoder) {
  273. v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, checkNil, true, d)
  274. if changed {
  275. *vp = v
  276. }
  277. }
  278. func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v []{{ .Elem }}, checkNil bool, canChange bool, d *Decoder) (_ []{{ .Elem }}, changed bool) {
  279. dd := d.d
  280. {{/* // if dd.isContainerType(valueTypeNil) { dd.TryDecodeAsNil() */}}
  281. if checkNil && dd.TryDecodeAsNil() {
  282. if v != nil {
  283. changed = true
  284. }
  285. return nil, changed
  286. }
  287. slh, containerLenS := d.decSliceHelperStart()
  288. if containerLenS == 0 {
  289. if canChange {
  290. if v == nil {
  291. v = []{{ .Elem }}{}
  292. } else if len(v) != 0 {
  293. v = v[:0]
  294. }
  295. changed = true
  296. }
  297. slh.End()
  298. return
  299. }
  300. if containerLenS > 0 {
  301. x2read := containerLenS
  302. var xtrunc bool
  303. if containerLenS > cap(v) {
  304. if canChange { {{/*
  305. // fast-path is for "basic" immutable types, so no need to copy them over
  306. // s := make([]{{ .Elem }}, decInferLen(containerLenS, d.h.MaxInitLen))
  307. // copy(s, v[:cap(v)])
  308. // v = s */}}
  309. var xlen int
  310. xlen, xtrunc = decInferLen(containerLenS, d.h.MaxInitLen, {{ .Size }})
  311. if xtrunc {
  312. if xlen <= cap(v) {
  313. v = v[:xlen]
  314. } else {
  315. v = make([]{{ .Elem }}, xlen)
  316. }
  317. } else {
  318. v = make([]{{ .Elem }}, xlen)
  319. }
  320. changed = true
  321. } else {
  322. d.arrayCannotExpand(len(v), containerLenS)
  323. }
  324. x2read = len(v)
  325. } else if containerLenS != len(v) {
  326. if canChange {
  327. v = v[:containerLenS]
  328. changed = true
  329. }
  330. } {{/* // all checks done. cannot go past len. */}}
  331. j := 0
  332. for ; j < x2read; j++ {
  333. slh.ElemContainerState(j)
  334. {{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
  335. }
  336. if xtrunc { {{/* // means canChange=true, changed=true already. */}}
  337. for ; j < containerLenS; j++ {
  338. v = append(v, {{ zerocmd .Elem }})
  339. slh.ElemContainerState(j)
  340. {{ if eq .Elem "interface{}" }}d.decode(&v[j]){{ else }}v[j] = {{ decmd .Elem }}{{ end }}
  341. }
  342. } else if !canChange {
  343. for ; j < containerLenS; j++ {
  344. slh.ElemContainerState(j)
  345. d.swallow()
  346. }
  347. }
  348. } else {
  349. breakFound := dd.CheckBreak() {{/* check break first, so we can initialize v with a capacity of 4 if necessary */}}
  350. if breakFound {
  351. if canChange {
  352. if v == nil {
  353. v = []{{ .Elem }}{}
  354. } else if len(v) != 0 {
  355. v = v[:0]
  356. }
  357. changed = true
  358. }
  359. slh.End()
  360. return
  361. }
  362. if cap(v) == 0 {
  363. v = make([]{{ .Elem }}, 1, 4)
  364. changed = true
  365. }
  366. j := 0
  367. for ; !breakFound; j++ {
  368. if j >= len(v) {
  369. if canChange {
  370. v = append(v, {{ zerocmd .Elem }})
  371. changed = true
  372. } else {
  373. d.arrayCannotExpand(len(v), j+1)
  374. }
  375. }
  376. slh.ElemContainerState(j)
  377. if j < len(v) { {{/* // all checks done. cannot go past len. */}}
  378. {{ if eq .Elem "interface{}" }}d.decode(&v[j])
  379. {{ else }}v[j] = {{ decmd .Elem }}{{ end }}
  380. } else {
  381. d.swallow()
  382. }
  383. breakFound = dd.CheckBreak()
  384. }
  385. if canChange && j < len(v) {
  386. v = v[:j]
  387. changed = true
  388. }
  389. }
  390. slh.End()
  391. return v, changed
  392. }
  393. {{end}}{{end}}{{end}}
  394. {{range .Values}}{{if not .Primitive}}{{if .MapKey }}
  395. {{/*
  396. Maps can change if they are
  397. - addressable (from a ptr)
  398. - settable (e.g. contained in an interface{})
  399. */}}
  400. func (f *decFnInfo) {{ .MethodNamePfx "fastpathDec" false }}R(rv reflect.Value) {
  401. if rv.CanAddr() {
  402. vp := rv.Addr().Interface().(*map[{{ .MapKey }}]{{ .Elem }})
  403. v, changed := fastpathTV.{{ .MethodNamePfx "Dec" false }}V(*vp, fastpathCheckNilFalse, true, f.d)
  404. if changed {
  405. *vp = v
  406. }
  407. } else {
  408. v := rv.Interface().(map[{{ .MapKey }}]{{ .Elem }})
  409. fastpathTV.{{ .MethodNamePfx "Dec" false }}V(v, fastpathCheckNilFalse, false, f.d)
  410. }
  411. }
  412. func (f fastpathT) {{ .MethodNamePfx "Dec" false }}X(vp *map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, d *Decoder) {
  413. v, changed := f.{{ .MethodNamePfx "Dec" false }}V(*vp, checkNil, true, d)
  414. if changed {
  415. *vp = v
  416. }
  417. }
  418. func (_ fastpathT) {{ .MethodNamePfx "Dec" false }}V(v map[{{ .MapKey }}]{{ .Elem }}, checkNil bool, canChange bool,
  419. d *Decoder) (_ map[{{ .MapKey }}]{{ .Elem }}, changed bool) {
  420. dd := d.d
  421. cr := d.cr
  422. {{/* // if dd.isContainerType(valueTypeNil) {dd.TryDecodeAsNil() */}}
  423. if checkNil && dd.TryDecodeAsNil() {
  424. if v != nil {
  425. changed = true
  426. }
  427. return nil, changed
  428. }
  429. containerLen := dd.ReadMapStart()
  430. if canChange && v == nil {
  431. xlen, _ := decInferLen(containerLen, d.h.MaxInitLen, {{ .Size }})
  432. v = make(map[{{ .MapKey }}]{{ .Elem }}, xlen)
  433. changed = true
  434. }
  435. {{ if eq .Elem "interface{}" }}mapGet := !d.h.MapValueReset && !d.h.InterfaceReset{{end}}
  436. var mk {{ .MapKey }}
  437. var mv {{ .Elem }}
  438. if containerLen > 0 {
  439. for j := 0; j < containerLen; j++ {
  440. if cr != nil { cr.sendContainerState(containerMapKey) }
  441. {{ if eq .MapKey "interface{}" }}mk = nil
  442. d.decode(&mk)
  443. if bv, bok := mk.([]byte); bok {
  444. mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
  445. }{{ else }}mk = {{ decmd .MapKey }}{{ end }}
  446. if cr != nil { cr.sendContainerState(containerMapValue) }
  447. {{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
  448. d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
  449. if v != nil {
  450. v[mk] = mv
  451. }
  452. }
  453. } else if containerLen < 0 {
  454. for j := 0; !dd.CheckBreak(); j++ {
  455. if cr != nil { cr.sendContainerState(containerMapKey) }
  456. {{ if eq .MapKey "interface{}" }}mk = nil
  457. d.decode(&mk)
  458. if bv, bok := mk.([]byte); bok {
  459. mk = d.string(bv) {{/* // maps cannot have []byte as key. switch to string. */}}
  460. }{{ else }}mk = {{ decmd .MapKey }}{{ end }}
  461. if cr != nil { cr.sendContainerState(containerMapValue) }
  462. {{ if eq .Elem "interface{}" }}if mapGet { mv = v[mk] } else { mv = nil }
  463. d.decode(&mv){{ else }}mv = {{ decmd .Elem }}{{ end }}
  464. if v != nil {
  465. v[mk] = mv
  466. }
  467. }
  468. }
  469. if cr != nil { cr.sendContainerState(containerMapEnd) }
  470. return v, changed
  471. }
  472. {{end}}{{end}}{{end}}