@@ -182,7 +182,7 @@ func PrefixMatcher(parts ...interface{}) (*SetMatcher, error) {
182
182
return nil , fmt .Errorf ("unexpected type %T" , t )
183
183
}
184
184
current = & SetMatcher {
185
- Members : []* SetMemberMatcher {{
185
+ members : []* SetMemberMatcher {{
186
186
Path : pattern ,
187
187
Child : current ,
188
188
}},
@@ -198,54 +198,61 @@ func MatchAnyPathElement() PathElementMatcher {
198
198
199
199
// MatchAnySet returns a SetMatcher that matches any set.
200
200
func MatchAnySet () * SetMatcher {
201
- return & SetMatcher {Wildcard : true }
201
+ return & SetMatcher {wildcard : true }
202
+ }
203
+
204
+ // NewSetMatcher returns a new SetMatcher.
205
+ // Wildcard members take precedent over non-wildcard members;
206
+ // all non-wildcard members are ignored if there is a wildcard members.
207
+ func NewSetMatcher (wildcard bool , members ... * SetMemberMatcher ) * SetMatcher {
208
+ sort .Sort (sortedMemberMatcher (members ))
209
+ return & SetMatcher {wildcard : wildcard , members : members }
202
210
}
203
211
204
212
// SetMatcher defines a pattern that matches fields in a Set.
205
213
// SetMatcher is structured much like a Set but with wildcard support.
206
214
type SetMatcher struct {
207
- // Wildcard indicates that all members and children are included in the match.
208
- // If set, the Members field is ignored.
209
- Wildcard bool
210
- // Members provides patterns to match the members of a Set.
211
- Members []* SetMemberMatcher
215
+ // wildcard indicates that all members and children are included in the match.
216
+ // If set, the members field is ignored.
217
+ wildcard bool
218
+ // members provides patterns to match the members of a Set.
219
+ // Wildcard members are sorted before non-wildcards and take precedent over
220
+ // non-wildcard members.
221
+ members sortedMemberMatcher
222
+ }
223
+
224
+ type sortedMemberMatcher []* SetMemberMatcher
225
+
226
+ func (s sortedMemberMatcher ) Len () int { return len (s ) }
227
+ func (s sortedMemberMatcher ) Less (i , j int ) bool { return s [i ].Path .Less (s [j ].Path ) }
228
+ func (s sortedMemberMatcher ) Swap (i , j int ) { s [i ], s [j ] = s [j ], s [i ] }
229
+ func (s sortedMemberMatcher ) Find (p PathElementMatcher ) (location int , ok bool ) {
230
+ return sort .Find (len (s ), func (i int ) int {
231
+ return s [i ].Path .Compare (p )
232
+ })
212
233
}
213
234
214
- // Merge merges two SetMatchers into a single SetMatcher that matches the field paths of both SetMatchers.
215
- // During the merge, Members of s2 with the same PathElementMatcher as a member of s are merged into the member of s.
216
- // All other members of s2 are appended to the resulting member list in their original relative order.
217
- // When members are merged, the child SetMatchers are merged by calling this function recursively.
235
+ // Merge merges s and s2 and returns a SetMatcher that matches all field paths matched by either s or s2.
236
+ // During the merge, members of s and s2 with the same PathElementMatcher merged into a single member
237
+ // with the children of each merged by calling this function recursively.
218
238
func (s * SetMatcher ) Merge (s2 * SetMatcher ) * SetMatcher {
219
- if s .Wildcard || s2 .Wildcard {
220
- return & SetMatcher {Wildcard : true }
221
- }
222
-
223
- // TODO: Optimize. This is O(n^2). In practice, usually a single member is being inserted at a time,
224
- // but that's still O(n). Sorting would help a ton.
225
- var unionedMembers []* SetMemberMatcher
226
- for _ , m := range s .Members {
227
- for _ , m2 := range s2 .Members {
228
- if m .Path .PathElement .Equals (m2 .Path .PathElement ) && m .Path .Wildcard == m2 .Path .Wildcard {
229
- unionedMembers = append (unionedMembers , & SetMemberMatcher {
230
- Path : m .Path ,
231
- Child : m .Child .Merge (m2 .Child ),
232
- })
233
- } else {
234
- unionedMembers = append (unionedMembers , m )
235
- }
236
- }
237
- }
238
- for _ , m2 := range s2 .Members {
239
- for _ , existing := range unionedMembers {
240
- if ! m2 .Path .PathElement .Equals (existing .Path .PathElement ) {
241
- unionedMembers = append (unionedMembers , m2 )
239
+ if s .wildcard || s2 .wildcard {
240
+ return NewSetMatcher (true )
241
+ }
242
+ merged := make (sortedMemberMatcher , len (s .members ), len (s .members )+ len (s2 .members ))
243
+ copy (merged , s .members )
244
+ for _ , m := range s2 .members {
245
+ if i , ok := s .members .Find (m .Path ); ok {
246
+ // since merged is a shallow copy, do not modify elements in place
247
+ merged [i ] = & SetMemberMatcher {
248
+ Path : merged [i ].Path ,
249
+ Child : merged [i ].Child .Merge (m .Child ),
242
250
}
251
+ } else {
252
+ merged = append (merged , m )
243
253
}
244
254
}
245
-
246
- return & SetMatcher {
247
- Members : unionedMembers ,
248
- }
255
+ return NewSetMatcher (false , merged ... ) // sort happens here
249
256
}
250
257
251
258
// SetMemberMatcher defines a pattern that matches the members of a Set.
@@ -274,15 +281,37 @@ type PathElementMatcher struct {
274
281
PathElement
275
282
}
276
283
284
+ func (p PathElementMatcher ) Equals (p2 PathElementMatcher ) bool {
285
+ return p .Wildcard != p2 .Wildcard && p .PathElement .Equals (p2 .PathElement )
286
+ }
287
+
288
+ func (p PathElementMatcher ) Less (p2 PathElementMatcher ) bool {
289
+ if p .Wildcard && ! p2 .Wildcard {
290
+ return true
291
+ } else if p2 .Wildcard {
292
+ return false
293
+ }
294
+ return p .PathElement .Less (p2 .PathElement )
295
+ }
296
+
297
+ func (p PathElementMatcher ) Compare (p2 PathElementMatcher ) int {
298
+ if p .Wildcard && ! p2 .Wildcard {
299
+ return - 1
300
+ } else if p2 .Wildcard {
301
+ return 1
302
+ }
303
+ return p .PathElement .Compare (p2 .PathElement )
304
+ }
305
+
277
306
// FilterIncludeMatches returns a Set with only the field paths that match.
278
307
func (s * Set ) FilterIncludeMatches (pattern * SetMatcher ) * Set {
279
- if pattern .Wildcard {
308
+ if pattern .wildcard {
280
309
return s
281
310
}
282
311
283
312
members := PathElementSet {}
284
313
for _ , m := range s .Members .members {
285
- for _ , pm := range pattern .Members {
314
+ for _ , pm := range pattern .members {
286
315
if pm .Path .Wildcard || pm .Path .PathElement .Equals (m ) {
287
316
members .Insert (m )
288
317
break
@@ -637,13 +666,13 @@ func (s *SetNodeMap) EnsureNamedFieldsAreMembers(sc *schema.Schema, tr schema.Ty
637
666
638
667
// FilterIncludeMatches returns a SetNodeMap with only the field paths that match the pattern.
639
668
func (s * SetNodeMap ) FilterIncludeMatches (pattern * SetMatcher ) * SetNodeMap {
640
- if pattern .Wildcard {
669
+ if pattern .wildcard {
641
670
return s
642
671
}
643
672
644
673
var out sortedSetNode
645
674
for _ , member := range s .members {
646
- for _ , c := range pattern .Members {
675
+ for _ , c := range pattern .members {
647
676
if c .Path .Wildcard || c .Path .PathElement .Equals (member .pathElement ) {
648
677
childSet := member .set .FilterIncludeMatches (c .Child )
649
678
if childSet .Size () > 0 {
@@ -727,7 +756,7 @@ func (t excludeFilter) Filter(set *Set) *Set {
727
756
// PrefixMatcher and MakePrefixMatcherOrDie can help create basic SetPatterns.
728
757
func NewIncludeMatcherFilter (patterns ... * SetMatcher ) Filter {
729
758
if len (patterns ) == 0 {
730
- return includeMatcherFilter {& SetMatcher {Wildcard : true }}
759
+ return includeMatcherFilter {& SetMatcher {wildcard : true }}
731
760
}
732
761
pattern := patterns [0 ]
733
762
for i := 1 ; i < len (patterns ); i ++ {
0 commit comments