@@ -17,11 +17,62 @@ limitations under the License.
17
17
package typed
18
18
19
19
import (
20
+ "sort"
21
+
20
22
"sigs.k8s.io/structured-merge-diff/fieldpath"
21
23
"sigs.k8s.io/structured-merge-diff/schema"
22
24
"sigs.k8s.io/structured-merge-diff/value"
23
25
)
24
26
27
+ type pathElementValueMap struct {
28
+ members sortedPathElementValues
29
+ }
30
+
31
+ type pathElementValue struct {
32
+ PathElement fieldpath.PathElement
33
+ Value value.Value
34
+ }
35
+
36
+ type sortedPathElementValues []pathElementValue
37
+
38
+ // Implement the sort interface; this would permit bulk creation, which would
39
+ // be faster than doing it one at a time via Insert.
40
+ func (spev sortedPathElementValues ) Len () int { return len (spev ) }
41
+ func (spev sortedPathElementValues ) Less (i , j int ) bool {
42
+ return spev [i ].PathElement .Less (spev [j ].PathElement )
43
+ }
44
+ func (spev sortedPathElementValues ) Swap (i , j int ) { spev [i ], spev [j ] = spev [j ], spev [i ] }
45
+
46
+ // Insert adds pe to the set.
47
+ func (s * pathElementValueMap ) Insert (pe fieldpath.PathElement , v value.Value ) {
48
+ loc := sort .Search (len (s .members ), func (i int ) bool {
49
+ return ! s .members [i ].PathElement .Less (pe )
50
+ })
51
+ if loc == len (s .members ) {
52
+ s .members = append (s .members , pathElementValue {pe , v })
53
+ return
54
+ }
55
+ if s .members [loc ].PathElement .Equals (pe ) {
56
+ return
57
+ }
58
+ s .members = append (s .members , pathElementValue {})
59
+ copy (s .members [loc + 1 :], s .members [loc :])
60
+ s .members [loc ] = pathElementValue {pe , v }
61
+ }
62
+
63
+ func (s * pathElementValueMap ) Get (pe fieldpath.PathElement ) * value.Value {
64
+ loc := sort .Search (len (s .members ), func (i int ) bool {
65
+ return ! s .members [i ].PathElement .Less (pe )
66
+ })
67
+ if loc == len (s .members ) {
68
+ return nil
69
+ }
70
+ if s .members [loc ].PathElement .Equals (pe ) {
71
+ return & s .members [loc ].Value
72
+ }
73
+ return nil
74
+ }
75
+
25
76
type mergingWalker struct {
26
77
errorFormatter
27
78
lhs * value.Value
@@ -168,7 +219,7 @@ func (w *mergingWalker) visitListItems(t schema.List, lhs, rhs *value.List) (err
168
219
rhsOrder := []fieldpath.PathElement {}
169
220
170
221
// First, collect all RHS children.
171
- observedRHS := map [ string ]value. Value {}
222
+ observedRHS := pathElementValueMap {}
172
223
if rhs != nil {
173
224
for i , child := range rhs .Items {
174
225
pe , err := listItemToPathElement (t , i , child )
@@ -179,17 +230,16 @@ func (w *mergingWalker) visitListItems(t schema.List, lhs, rhs *value.List) (err
179
230
// this element.
180
231
continue
181
232
}
182
- keyStr := pe .String ()
183
- if _ , found := observedRHS [keyStr ]; found {
184
- errs = append (errs , w .errorf ("rhs: duplicate entries for key %v" , keyStr )... )
233
+ if observedRHS .Get (pe ) != nil {
234
+ errs = append (errs , w .errorf ("rhs: duplicate entries for key %v" , pe .String ())... )
185
235
}
186
- observedRHS [ keyStr ] = child
236
+ observedRHS . Insert ( pe , child )
187
237
rhsOrder = append (rhsOrder , pe )
188
238
}
189
239
}
190
240
191
241
// Then merge with LHS children.
192
- observedLHS := map [ string ] struct {} {}
242
+ observedLHS := fieldpath. PathElementSet {}
193
243
if lhs != nil {
194
244
for i , child := range lhs .Items {
195
245
pe , err := listItemToPathElement (t , i , child )
@@ -200,39 +250,38 @@ func (w *mergingWalker) visitListItems(t schema.List, lhs, rhs *value.List) (err
200
250
// this element.
201
251
continue
202
252
}
203
- keyStr := pe .String ()
204
- if _ , found := observedLHS [keyStr ]; found {
205
- errs = append (errs , w .errorf ("lhs: duplicate entries for key %v" , keyStr )... )
253
+ if observedLHS .Has (pe ) {
254
+ errs = append (errs , w .errorf ("lhs: duplicate entries for key %v" , pe .String ())... )
206
255
continue
207
256
}
208
- observedLHS [ keyStr ] = struct {}{}
257
+ observedLHS . Insert ( pe )
209
258
w2 := w .prepareDescent (pe , t .ElementType )
210
259
w2 .lhs = & child
211
- if rchild , ok := observedRHS [ keyStr ]; ok {
212
- w2 .rhs = & rchild
260
+ if rchild := observedRHS . Get ( pe ); rchild != nil {
261
+ w2 .rhs = rchild
213
262
}
214
263
if newErrs := w2 .merge (); len (newErrs ) > 0 {
215
264
errs = append (errs , newErrs ... )
216
265
} else if w2 .out != nil {
217
266
out .Items = append (out .Items , * w2 .out )
218
267
}
219
268
w .finishDescent (w2 )
220
- // Keep track of children that have been handled
221
- delete (observedRHS , keyStr )
222
269
}
223
270
}
224
271
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 )
272
+ for _ , pe := range rhsOrder {
273
+ if observedLHS .Has (pe ) {
274
+ continue
275
+ }
276
+ value := observedRHS .Get (pe )
277
+ w2 := w .prepareDescent (pe , t .ElementType )
278
+ w2 .rhs = value
279
+ if newErrs := w2 .merge (); len (newErrs ) > 0 {
280
+ errs = append (errs , newErrs ... )
281
+ } else if w2 .out != nil {
282
+ out .Items = append (out .Items , * w2 .out )
235
283
}
284
+ w .finishDescent (w2 )
236
285
}
237
286
238
287
if len (out .Items ) > 0 {
0 commit comments