summaryrefslogtreecommitdiff
path: root/vendor/github.com/ugorji/go/codec/fastpath.go.tmpl
blob: db60ea8376008a85fdd9fc38e6d82044d86d5df7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//go:build !notfastpath && !codec.notfastpath

// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.

// Code generated from fastpath.go.tmpl - DO NOT EDIT.

package codec

// Fast path functions try to create a fast path encode or decode implementation
// for common maps and slices.
//
// We define the functions and register them in this single file
// so as not to pollute the encode.go and decode.go, and create a dependency in there.
// This file can be omitted without causing a build failure.
//
// The advantage of fast paths is:
//	  - Many calls bypass reflection altogether
// 
// Currently support
//	  - slice of all builtin types (numeric, bool, string, []byte)
//    - maps of builtin types to builtin or interface{} type, EXCEPT FOR
//      keys of type uintptr, int8/16/32, uint16/32, float32/64, bool, interface{}
//      AND values of type type int8/16/32, uint16/32
// This should provide adequate "typical" implementations.
// 
// Note that fast track decode functions must handle values for which an address cannot be obtained.
// For example: 
//	 m2 := map[string]int{}
//	 p2 := []interface{}{m2}
//	 // decoding into p2 will bomb if fast track functions do not treat like unaddressable.
// 

{{/*
// ----------------
fastpathEncMap<KV>R func (mapped to type id), routes to:
- ft.EncMap<KV>V

fastpathEncSlice<E>R func (mapped to type id), delegates to one of:
- ft.EncSlice<E>V
- ft.EncAsMapSlice<E>V (when mapbyslice ie f.ti.mbs=true)

// ----------------
fastpathDecSlice<E>R func (mapped to type id), delegates to:
- ft.DecSliceIntfY  (when slice CAN be updated)
- ft.DecSliceIntfN  (when slice CANNOT be updated e.g. from array or non-addressable slice)

fastpathDecMap<KV>R func (mapped to type id), routes to
- ft.DecMap<KV>L  (handles ptr which is changeable, and non-pointer which cannot be made if nil)

// ----------------
NOTE:
- fastpath typeswitch directly calls the secondary methods for builtin maps/slices with appropriate nil handling:
  - except EncAsMapSlice<E>V which only applies to wrapper types not those in the switch
- fastpathEncXXX functions mapped to type ID MUST do nil-checks during encode
  - they are only called by decodeValue/encodeValue or other code (same way kMap et al are called)
*/ -}}

import (
	"reflect"
	"sort"
	"slices"
)

const fastpathEnabled = true

{{/*
const fastpathMapBySliceErrMsg = "mapBySlice requires even slice length, but got %v"
*/ -}}

type fastpathARtid [{{ .FastpathLen }}]uintptr

type fastpathRtRtid struct {
	rtid  uintptr
	rt    reflect.Type
}
type fastpathARtRtid [{{ .FastpathLen }}]fastpathRtRtid

var (
	fastpathAvRtidArr fastpathARtid
	fastpathAvRtRtidArr fastpathARtRtid
	fastpathAvRtid = fastpathAvRtidArr[:]
	fastpathAvRtRtid = fastpathAvRtRtidArr[:]
)

func fastpathAvIndex(rtid uintptr) (i uint, ok bool) {
	return searchRtids(fastpathAvRtid, rtid)
}

func init() {
	var i uint = 0
	fn := func(v interface{}) {
		xrt := reflect.TypeOf(v)
		xrtid := rt2id(xrt)
		xptrtid := rt2id(reflect.PointerTo(xrt))
		{{- /* only the base slice/map rtid is put in fastpathAvIndex, since we only handle slices/map/array */}}
        fastpathAvRtid[i] = xrtid
		fastpathAvRtRtid[i] = fastpathRtRtid{ rtid: xrtid, rt: xrt }
		{{- /* fastpath type switches however handle slices/map/array, and pointers to them */}}
		encBuiltinRtids = append(encBuiltinRtids, xrtid, xptrtid)
		decBuiltinRtids = append(decBuiltinRtids, xrtid, xptrtid)
		i++
	}
	{{/* do not register []byte in fastpath */}}
	{{range .Values}}{{if not .Primitive}}{{if not .MapKey -}}
	fn([]{{ .Elem }}(nil))
	{{end}}{{end}}{{end}}
	
	{{range .Values}}{{if not .Primitive}}{{if .MapKey -}}
	fn(map[{{ .MapKey }}]{{ .Elem }}(nil))
	{{end}}{{end}}{{end}}

	sort.Slice(fastpathAvRtid, func(i, j int) bool { return fastpathAvRtid[i] < fastpathAvRtid[j] })
	sort.Slice(fastpathAvRtRtid, func(i, j int) bool { return fastpathAvRtRtid[i].rtid < fastpathAvRtRtid[j].rtid })
	slices.Sort(encBuiltinRtids)
	slices.Sort(decBuiltinRtids)
}
	
func fastpathDecodeSetZeroTypeSwitch(iv interface{}) bool {
	switch v := iv.(type) {
{{range .Values}}{{if not .Primitive}}{{if not .MapKey -}}
	case *[]{{ .Elem }}: 
		*v = nil
{{end}}{{end}}{{end}}
{{range .Values}}{{if not .Primitive}}{{if .MapKey -}}
	case *map[{{ .MapKey }}]{{ .Elem }}: 
		*v = nil 
{{end}}{{end}}{{end}}
	default:
		_ = v // workaround https://github.com/golang/go/issues/12927 seen in go1.4
		return false
	}
	return true
}