Skip to content

Commit bea3b75

Browse files
committed
propagate memory management improvements to validator
1 parent b933a62 commit bea3b75

File tree

1 file changed

+45
-17
lines changed

1 file changed

+45
-17
lines changed

typed/validate.go

+45-17
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,36 @@ type validatingObjectWalker struct {
4949

5050
// internal housekeeping--don't set when constructing.
5151
inLeaf bool // Set to true if we're in a "big leaf"--atomic map/list
52+
53+
// Allocate only as many walkers as needed for the depth by storing them here.
54+
spareWalkers *[]*validatingObjectWalker
55+
}
56+
57+
func (v *validatingObjectWalker) prepareDescent(pe fieldpath.PathElement, tr schema.TypeRef) *validatingObjectWalker {
58+
if v.spareWalkers == nil {
59+
// first descent.
60+
v.spareWalkers = &[]*validatingObjectWalker{}
61+
}
62+
var v2 *validatingObjectWalker
63+
if n := len(*v.spareWalkers); n > 0 {
64+
v2, *v.spareWalkers = (*v.spareWalkers)[n-1], (*v.spareWalkers)[:n-1]
65+
} else {
66+
v2 = &validatingObjectWalker{}
67+
}
68+
*v2 = *v
69+
v2.typeRef = tr
70+
v2.errorFormatter.descend(pe)
71+
return v2
72+
}
73+
74+
func (v *validatingObjectWalker) finishDescent(v2 *validatingObjectWalker) {
75+
// if the descent caused a realloc, ensure that we reuse the buffer
76+
// for the next sibling.
77+
v.errorFormatter = v2.errorFormatter.parent()
78+
*v.spareWalkers = append(*v.spareWalkers, v2)
5279
}
5380

54-
func (v validatingObjectWalker) validate() ValidationErrors {
81+
func (v *validatingObjectWalker) validate() ValidationErrors {
5582
return resolveSchema(v.schema, v.typeRef, &v.value, v)
5683
}
5784

@@ -87,7 +114,7 @@ func (v *validatingObjectWalker) doNode() {
87114
}
88115
}
89116

90-
func (v validatingObjectWalker) doScalar(t schema.Scalar) ValidationErrors {
117+
func (v *validatingObjectWalker) doScalar(t schema.Scalar) ValidationErrors {
91118
if errs := v.validateScalar(t, &v.value, ""); len(errs) > 0 {
92119
return errs
93120
}
@@ -98,7 +125,7 @@ func (v validatingObjectWalker) doScalar(t schema.Scalar) ValidationErrors {
98125
return nil
99126
}
100127

101-
func (v validatingObjectWalker) visitListItems(t schema.List, list *value.List) (errs ValidationErrors) {
128+
func (v *validatingObjectWalker) visitListItems(t schema.List, list *value.List) (errs ValidationErrors) {
102129
observedKeys := map[string]struct{}{}
103130
for i, child := range list.Items {
104131
pe, err := listItemToPathElement(t, i, child)
@@ -114,18 +141,17 @@ func (v validatingObjectWalker) visitListItems(t schema.List, list *value.List)
114141
errs = append(errs, v.errorf("duplicate entries for key %v", keyStr)...)
115142
}
116143
observedKeys[keyStr] = struct{}{}
117-
v2 := v
118-
v2.errorFormatter.descend(pe)
144+
v2 := v.prepareDescent(pe, t.ElementType)
119145
v2.value = child
120-
v2.typeRef = t.ElementType
121146
errs = append(errs, v2.validate()...)
122147

123148
v2.doNode()
149+
v.finishDescent(v2)
124150
}
125151
return errs
126152
}
127153

128-
func (v validatingObjectWalker) doList(t schema.List) (errs ValidationErrors) {
154+
func (v *validatingObjectWalker) doList(t schema.List) (errs ValidationErrors) {
129155
list, err := listValue(v.value)
130156
if err != nil {
131157
return v.error(err)
@@ -144,7 +170,7 @@ func (v validatingObjectWalker) doList(t schema.List) (errs ValidationErrors) {
144170
return errs
145171
}
146172

147-
func (v validatingObjectWalker) visitMapItems(t schema.Map, m *value.Map) (errs ValidationErrors) {
173+
func (v *validatingObjectWalker) visitMapItems(t schema.Map, m *value.Map) (errs ValidationErrors) {
148174
fieldTypes := map[string]schema.TypeRef{}
149175
for i := range t.Fields {
150176
// I don't want to use the loop variable since a reference
@@ -153,25 +179,27 @@ func (v validatingObjectWalker) visitMapItems(t schema.Map, m *value.Map) (errs
153179
fieldTypes[f.Name] = f.Type
154180
}
155181

156-
for _, item := range m.Items {
157-
v2 := v
158-
name := item.Name
159-
v2.errorFormatter.descend(fieldpath.PathElement{FieldName: &name})
160-
v2.value = item.Value
182+
for i := range m.Items {
183+
item := &m.Items[i]
184+
pe := fieldpath.PathElement{FieldName: &item.Name}
161185

162-
var ok bool
163-
if v2.typeRef, ok = fieldTypes[name]; ok {
186+
if tr, ok := fieldTypes[item.Name]; ok {
187+
v2 := v.prepareDescent(pe, tr)
188+
v2.value = item.Value
164189
errs = append(errs, v2.validate()...)
190+
v.finishDescent(v2)
165191
} else {
166-
v2.typeRef = t.ElementType
192+
v2 := v.prepareDescent(pe, t.ElementType)
193+
v2.value = item.Value
167194
errs = append(errs, v2.validate()...)
168195
v2.doNode()
196+
v.finishDescent(v2)
169197
}
170198
}
171199
return errs
172200
}
173201

174-
func (v validatingObjectWalker) doMap(t schema.Map) (errs ValidationErrors) {
202+
func (v *validatingObjectWalker) doMap(t schema.Map) (errs ValidationErrors) {
175203
m, err := mapValue(v.value)
176204
if err != nil {
177205
return v.error(err)

0 commit comments

Comments
 (0)