File: inline.go

package info (click to toggle)
golang-github-tinylib-msgp 1.2.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 836 kB
  • sloc: makefile: 47
file content (170 lines) | stat: -rw-r--r-- 4,026 bytes parent folder | download | duplicates (2)
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package parse

import (
	"sort"

	"github.com/tinylib/msgp/gen"
)

// This file defines when and how we
// propagate type information from
// one type declaration to another.
// After the processing pass, every
// non-primitive type is marshalled/unmarshalled/etc.
// through a function call. Here, we propagate
// the type information into the caller's type
// tree *if* the child type is simple enough.
//
// For example, types like
//
//    type A [4]int
//
// will get pushed into parent methods,
// whereas types like
//
//    type B [3]map[string]struct{A, B [4]string}
//
// will not.

// this is an approximate measure
// of the number of children in a node
const maxComplex = 5

// begin recursive search for identities with the
// given name and replace them with e
func (f *FileSet) findShim(id string, e gen.Elem, addID bool) {
	for name, el := range f.Identities {
		pushstate(name)
		switch el := el.(type) {
		case *gen.Struct:
			for i := range el.Fields {
				f.nextShim(&el.Fields[i].FieldElem, id, e)
			}
		case *gen.Array:
			f.nextShim(&el.Els, id, e)
		case *gen.Slice:
			f.nextShim(&el.Els, id, e)
		case *gen.Map:
			f.nextShim(&el.Value, id, e)
		case *gen.Ptr:
			f.nextShim(&el.Value, id, e)
		}
		popstate()
	}
	if addID {
		f.Identities[id] = e
	}
}

func (f *FileSet) nextShim(ref *gen.Elem, id string, e gen.Elem) {
	if (*ref).TypeName() == id {
		vn := (*ref).Varname()
		*ref = e.Copy()
		(*ref).SetVarname(vn)
	} else {
		switch el := (*ref).(type) {
		case *gen.Struct:
			for i := range el.Fields {
				f.nextShim(&el.Fields[i].FieldElem, id, e)
			}
		case *gen.Array:
			f.nextShim(&el.Els, id, e)
		case *gen.Slice:
			f.nextShim(&el.Els, id, e)
		case *gen.Map:
			f.nextShim(&el.Value, id, e)
		case *gen.Ptr:
			f.nextShim(&el.Value, id, e)
		}
	}
}

// propInline identifies and inlines candidates
func (f *FileSet) propInline() {
	type gelem struct {
		name string
		el   gen.Elem
	}

	all := make([]gelem, 0, len(f.Identities))

	for name, el := range f.Identities {
		all = append(all, gelem{name: name, el: el})
	}

	// make sure we process inlining determinstically:
	// start with the least-complex elems;
	// use identifier names as a tie-breaker
	sort.Slice(all, func(i, j int) bool {
		ig, jg := &all[i], &all[j]
		ic, jc := ig.el.Complexity(), jg.el.Complexity()
		return ic < jc || (ic == jc && ig.name < jg.name)
	})

	for i := range all {
		name := all[i].name
		pushstate(name)
		switch el := all[i].el.(type) {
		case *gen.Struct:
			for i := range el.Fields {
				f.nextInline(&el.Fields[i].FieldElem, name)
			}
		case *gen.Array:
			f.nextInline(&el.Els, name)
		case *gen.Slice:
			f.nextInline(&el.Els, name)
		case *gen.Map:
			f.nextInline(&el.Value, name)
		case *gen.Ptr:
			f.nextInline(&el.Value, name)
		}
		popstate()
	}
}

const fatalloop = `detected infinite recursion in inlining loop!
Please file a bug at github.com/tinylib/msgp/issues!
Thanks!
`

func (f *FileSet) nextInline(ref *gen.Elem, root string) {
	switch el := (*ref).(type) {
	case *gen.BaseElem:
		// ensure that we're not inlining
		// a type into itself
		typ := el.TypeName()
		if el.Value == gen.IDENT && typ != root {
			if node, ok := f.Identities[typ]; ok && node.Complexity() < maxComplex {
				infof("inlining %s\n", typ)

				// This should never happen; it will cause
				// infinite recursion.
				if node == *ref {
					panic(fatalloop)
				}

				*ref = node.Copy()
				f.nextInline(ref, node.TypeName())
			} else if !ok && !el.Resolved() {
				// this is the point at which we're sure that
				// we've got a type that isn't a primitive,
				// a library builtin, or a processed type
				warnf("unresolved identifier: %s\n", typ)
			}
		}
	case *gen.Struct:
		for i := range el.Fields {
			f.nextInline(&el.Fields[i].FieldElem, root)
		}
	case *gen.Array:
		f.nextInline(&el.Els, root)
	case *gen.Slice:
		f.nextInline(&el.Els, root)
	case *gen.Map:
		f.nextInline(&el.Value, root)
	case *gen.Ptr:
		f.nextInline(&el.Value, root)
	default:
		panic("bad elem type")
	}
}