Skip to content

Commit 9acd93a

Browse files
author
Antoine Pelisse
committed
Create map of PathElement to Value and use it instead of Strings
1 parent 3faeeaf commit 9acd93a

File tree

3 files changed

+150
-23
lines changed

3 files changed

+150
-23
lines changed

fieldpath/pathelementmap.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package fieldpath
18+
19+
import (
20+
"sort"
21+
22+
"sigs.k8s.io/structured-merge-diff/value"
23+
)
24+
25+
// PathElementValueMap is a map from PathElement to value.Value.
26+
//
27+
// TODO(apelisse): We have multiple very similar implementation of this
28+
// for PathElementSet and SetNodeMap, so we could probably share the
29+
// code.
30+
type PathElementValueMap struct {
31+
members sortedPathElementValues
32+
}
33+
34+
type pathElementValue struct {
35+
PathElement PathElement
36+
Value value.Value
37+
}
38+
39+
type sortedPathElementValues []pathElementValue
40+
41+
// Implement the sort interface; this would permit bulk creation, which would
42+
// be faster than doing it one at a time via Insert.
43+
func (spev sortedPathElementValues) Len() int { return len(spev) }
44+
func (spev sortedPathElementValues) Less(i, j int) bool {
45+
return spev[i].PathElement.Less(spev[j].PathElement)
46+
}
47+
func (spev sortedPathElementValues) Swap(i, j int) { spev[i], spev[j] = spev[j], spev[i] }
48+
49+
// Insert adds the pathelement and associated value in the map.
50+
func (s *PathElementValueMap) Insert(pe PathElement, v value.Value) {
51+
loc := sort.Search(len(s.members), func(i int) bool {
52+
return !s.members[i].PathElement.Less(pe)
53+
})
54+
if loc == len(s.members) {
55+
s.members = append(s.members, pathElementValue{pe, v})
56+
return
57+
}
58+
if s.members[loc].PathElement.Equals(pe) {
59+
return
60+
}
61+
s.members = append(s.members, pathElementValue{})
62+
copy(s.members[loc+1:], s.members[loc:])
63+
s.members[loc] = pathElementValue{pe, v}
64+
}
65+
66+
// Get retrieves the value associated with the given PathElement from the map.
67+
// (nil, false) is returned if there is no such PathElement.
68+
func (s *PathElementValueMap) Get(pe PathElement) (value.Value, bool) {
69+
loc := sort.Search(len(s.members), func(i int) bool {
70+
return !s.members[i].PathElement.Less(pe)
71+
})
72+
if loc == len(s.members) {
73+
return value.Value{}, false
74+
}
75+
if s.members[loc].PathElement.Equals(pe) {
76+
return s.members[loc].Value, true
77+
}
78+
return value.Value{}, false
79+
}

fieldpath/pathelementmap_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package fieldpath
18+
19+
import (
20+
"testing"
21+
22+
"sigs.k8s.io/structured-merge-diff/value"
23+
)
24+
25+
func TestPathElementValueMap(t *testing.T) {
26+
m := PathElementValueMap{}
27+
28+
if _, ok := m.Get(PathElement{FieldName: strptr("onion")}); ok {
29+
t.Fatal("Unexpected path-element found in empty map")
30+
}
31+
32+
m.Insert(PathElement{FieldName: strptr("carrot")}, value.StringValue("knife"))
33+
m.Insert(PathElement{FieldName: strptr("chive")}, value.IntValue(2))
34+
35+
if _, ok := m.Get(PathElement{FieldName: strptr("onion")}); ok {
36+
t.Fatal("Unexpected path-element in map")
37+
}
38+
39+
if val, ok := m.Get(PathElement{FieldName: strptr("carrot")}); !ok {
40+
t.Fatal("Missing path-element in map")
41+
} else if !val.Equals(value.StringValue("knife")) {
42+
t.Fatalf("Unexpected value found: %#v", val)
43+
}
44+
45+
if val, ok := m.Get(PathElement{FieldName: strptr("chive")}); !ok {
46+
t.Fatal("Missing path-element in map")
47+
} else if !val.Equals(value.IntValue(2)) {
48+
t.Fatalf("Unexpected value found: %#v", val)
49+
}
50+
}

typed/merge.go

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func (w *mergingWalker) visitListItems(t *schema.List, lhs, rhs *value.List) (er
168168
rhsOrder := []fieldpath.PathElement{}
169169

170170
// First, collect all RHS children.
171-
observedRHS := map[string]value.Value{}
171+
observedRHS := fieldpath.PathElementValueMap{}
172172
if rhs != nil {
173173
for i, child := range rhs.Items {
174174
pe, err := listItemToPathElement(t, i, child)
@@ -179,17 +179,16 @@ func (w *mergingWalker) visitListItems(t *schema.List, lhs, rhs *value.List) (er
179179
// this element.
180180
continue
181181
}
182-
keyStr := pe.String()
183-
if _, found := observedRHS[keyStr]; found {
184-
errs = append(errs, w.errorf("rhs: duplicate entries for key %v", keyStr)...)
182+
if _, ok := observedRHS.Get(pe); ok {
183+
errs = append(errs, w.errorf("rhs: duplicate entries for key %v", pe.String())...)
185184
}
186-
observedRHS[keyStr] = child
185+
observedRHS.Insert(pe, child)
187186
rhsOrder = append(rhsOrder, pe)
188187
}
189188
}
190189

191190
// Then merge with LHS children.
192-
observedLHS := map[string]struct{}{}
191+
observedLHS := fieldpath.PathElementSet{}
193192
if lhs != nil {
194193
for i, child := range lhs.Items {
195194
pe, err := listItemToPathElement(t, i, child)
@@ -200,15 +199,14 @@ func (w *mergingWalker) visitListItems(t *schema.List, lhs, rhs *value.List) (er
200199
// this element.
201200
continue
202201
}
203-
keyStr := pe.String()
204-
if _, found := observedLHS[keyStr]; found {
205-
errs = append(errs, w.errorf("lhs: duplicate entries for key %v", keyStr)...)
202+
if observedLHS.Has(pe) {
203+
errs = append(errs, w.errorf("lhs: duplicate entries for key %v", pe.String())...)
206204
continue
207205
}
208-
observedLHS[keyStr] = struct{}{}
206+
observedLHS.Insert(pe)
209207
w2 := w.prepareDescent(pe, t.ElementType)
210208
w2.lhs = &child
211-
if rchild, ok := observedRHS[keyStr]; ok {
209+
if rchild, ok := observedRHS.Get(pe); ok {
212210
w2.rhs = &rchild
213211
}
214212
if newErrs := w2.merge(); len(newErrs) > 0 {
@@ -217,22 +215,22 @@ func (w *mergingWalker) visitListItems(t *schema.List, lhs, rhs *value.List) (er
217215
out.Items = append(out.Items, *w2.out)
218216
}
219217
w.finishDescent(w2)
220-
// Keep track of children that have been handled
221-
delete(observedRHS, keyStr)
222218
}
223219
}
224220

225-
for _, rhsToCheck := range rhsOrder {
226-
if unmergedChild, ok := observedRHS[rhsToCheck.String()]; ok {
227-
w2 := w.prepareDescent(rhsToCheck, t.ElementType)
228-
w2.rhs = &unmergedChild
229-
if newErrs := w2.merge(); len(newErrs) > 0 {
230-
errs = append(errs, newErrs...)
231-
} else if w2.out != nil {
232-
out.Items = append(out.Items, *w2.out)
233-
}
234-
w.finishDescent(w2)
221+
for _, pe := range rhsOrder {
222+
if observedLHS.Has(pe) {
223+
continue
224+
}
225+
value, _ := observedRHS.Get(pe)
226+
w2 := w.prepareDescent(pe, t.ElementType)
227+
w2.rhs = &value
228+
if newErrs := w2.merge(); len(newErrs) > 0 {
229+
errs = append(errs, newErrs...)
230+
} else if w2.out != nil {
231+
out.Items = append(out.Items, *w2.out)
235232
}
233+
w.finishDescent(w2)
236234
}
237235

238236
if len(out.Items) > 0 {

0 commit comments

Comments
 (0)