@@ -35,7 +35,7 @@ type PathElement struct {
35
35
// Key selects the list element which has fields matching those given.
36
36
// The containing object must be an associative list with map typed
37
37
// elements.
38
- Key [] value.Field
38
+ Key * value.Map
39
39
40
40
// Value selects the list element with the given value. The containing
41
41
// object must be an associative list with a primitive typed element
@@ -47,14 +47,62 @@ type PathElement struct {
47
47
Index * int
48
48
}
49
49
50
+ // Less provides an order for path elements.
51
+ func (e PathElement ) Less (rhs PathElement ) bool {
52
+ if e .FieldName != nil {
53
+ if rhs .FieldName == nil {
54
+ return true
55
+ }
56
+ return * e .FieldName < * rhs .FieldName
57
+ } else if rhs .FieldName != nil {
58
+ return false
59
+ }
60
+
61
+ if e .Key != nil {
62
+ if rhs .Key == nil {
63
+ return true
64
+ }
65
+ return e .Key .Less (rhs .Key )
66
+ } else if rhs .Key != nil {
67
+ return false
68
+ }
69
+
70
+ if e .Value != nil {
71
+ if rhs .Value == nil {
72
+ return true
73
+ }
74
+ return e .Value .Less (* rhs .Value )
75
+ } else if rhs .Value != nil {
76
+ return false
77
+ }
78
+
79
+ if e .Index != nil {
80
+ if rhs .Index == nil {
81
+ return true
82
+ }
83
+ return * e .Index < * rhs .Index
84
+ } else if rhs .Index != nil {
85
+ // Yes, I know the next statement is the same. But this way
86
+ // the obvious way of extending the function wil be bug-free.
87
+ return false
88
+ }
89
+
90
+ return false
91
+ }
92
+
93
+ // Equals returns true if both path elements are equal.
94
+ func (e PathElement ) Equals (rhs PathElement ) bool {
95
+ return ! e .Less (rhs ) && ! rhs .Less (e )
96
+ }
97
+
50
98
// String presents the path element as a human-readable string.
51
99
func (e PathElement ) String () string {
52
100
switch {
53
101
case e .FieldName != nil :
54
102
return "." + * e .FieldName
55
- case len ( e .Key ) > 0 :
56
- strs := make ([]string , len (e .Key ))
57
- for i , k := range e .Key {
103
+ case e .Key != nil :
104
+ strs := make ([]string , len (e .Key . Items ))
105
+ for i , k := range e .Key . Items {
58
106
strs [i ] = fmt .Sprintf ("%v=%v" , k .Name , k .Value )
59
107
}
60
108
// The order must be canonical, since we use the string value
@@ -92,62 +140,104 @@ func KeyByFields(nameValues ...interface{}) []value.Field {
92
140
// PathElementSet is a set of path elements.
93
141
// TODO: serialize as a list.
94
142
type PathElementSet struct {
95
- // The strange construction is because there's no way to test
96
- // PathElements for equality (it can't be used as a key for a map).
97
- members map [string ]PathElement
143
+ members sortedPathElements
98
144
}
99
145
146
+ type sortedPathElements []PathElement
147
+
148
+ // Implement the sort interface; this would permit bulk creation, which would
149
+ // be faster than doing it one at a time via Insert.
150
+ func (spe sortedPathElements ) Len () int { return len (spe ) }
151
+ func (spe sortedPathElements ) Less (i , j int ) bool { return spe [i ].Less (spe [j ]) }
152
+ func (spe sortedPathElements ) Swap (i , j int ) { spe [i ], spe [j ] = spe [j ], spe [i ] }
153
+
100
154
// Insert adds pe to the set.
101
155
func (s * PathElementSet ) Insert (pe PathElement ) {
102
- serialized := pe . String ()
103
- if s .members == nil {
104
- s . members = map [ string ] PathElement {
105
- serialized : pe ,
106
- }
156
+ loc := sort . Search ( len ( s . members ), func ( i int ) bool {
157
+ return ! s .members [ i ]. Less ( pe )
158
+ })
159
+ if loc == len ( s . members ) {
160
+ s . members = append ( s . members , pe )
107
161
return
108
162
}
109
- if _ , ok := s .members [serialized ]; ! ok {
110
- s .members [serialized ] = pe
163
+ if s .members [loc ].Equals (pe ) {
164
+ return
165
+ }
166
+ n := len (s .members ) - 1
167
+ s .members = append (s .members , s .members [n ])
168
+ for n > loc {
169
+ s .members [n ] = s .members [n - 1 ]
170
+ n --
111
171
}
172
+ s .members [loc ] = pe
112
173
}
113
174
114
175
// Union returns a set containing elements that appear in either s or s2.
115
176
func (s * PathElementSet ) Union (s2 * PathElementSet ) * PathElementSet {
116
- out := & PathElementSet {
117
- members : map [string ]PathElement {},
177
+ out := & PathElementSet {}
178
+
179
+ i , j := 0 , 0
180
+ for i < len (s .members ) && j < len (s2 .members ) {
181
+ if s .members [i ].Less (s2 .members [j ]) {
182
+ out .members = append (out .members , s .members [i ])
183
+ i ++
184
+ } else {
185
+ out .members = append (out .members , s2 .members [j ])
186
+ if ! s2 .members [j ].Less (s .members [i ]) {
187
+ i ++
188
+ }
189
+ j ++
190
+ }
118
191
}
119
- for k , v := range s .members {
120
- out .members [k ] = v
192
+
193
+ if i < len (s .members ) {
194
+ out .members = append (out .members , s .members [i :]... )
121
195
}
122
- for k , v := range s2 .members {
123
- out .members [ k ] = v
196
+ if j < len ( s2 .members ) {
197
+ out .members = append ( out . members , s2 . members [ j :] ... )
124
198
}
125
199
return out
126
200
}
127
201
128
202
// Intersection returns a set containing elements which appear in both s and s2.
129
203
func (s * PathElementSet ) Intersection (s2 * PathElementSet ) * PathElementSet {
130
- out := & PathElementSet {
131
- members : map [string ]PathElement {},
132
- }
133
- for k , v := range s .members {
134
- if _ , ok := s2 .members [k ]; ok {
135
- out .members [k ] = v
204
+ out := & PathElementSet {}
205
+
206
+ i , j := 0 , 0
207
+ for i < len (s .members ) && j < len (s2 .members ) {
208
+ if s .members [i ].Less (s2 .members [j ]) {
209
+ i ++
210
+ } else {
211
+ if ! s2 .members [j ].Less (s .members [i ]) {
212
+ out .members = append (out .members , s .members [i ])
213
+ i ++
214
+ }
215
+ j ++
136
216
}
137
217
}
218
+
138
219
return out
139
220
}
140
221
141
222
// Difference returns a set containing elements which appear in s but not in s2.
142
223
func (s * PathElementSet ) Difference (s2 * PathElementSet ) * PathElementSet {
143
- out := & PathElementSet {
144
- members : map [string ]PathElement {},
145
- }
146
- for k , v := range s .members {
147
- if _ , ok := s2 .members [k ]; ! ok {
148
- out .members [k ] = v
224
+ out := & PathElementSet {}
225
+
226
+ i , j := 0 , 0
227
+ for i < len (s .members ) && j < len (s2 .members ) {
228
+ if s .members [i ].Less (s2 .members [j ]) {
229
+ out .members = append (out .members , s .members [i ])
230
+ i ++
231
+ } else {
232
+ if ! s2 .members [j ].Less (s .members [i ]) {
233
+ i ++
234
+ }
235
+ j ++
149
236
}
150
237
}
238
+ if i < len (s .members ) {
239
+ out .members = append (out .members , s .members [i :]... )
240
+ }
151
241
return out
152
242
}
153
243
@@ -156,11 +246,16 @@ func (s *PathElementSet) Size() int { return len(s.members) }
156
246
157
247
// Has returns true if pe is a member of the set.
158
248
func (s * PathElementSet ) Has (pe PathElement ) bool {
159
- if s .members == nil {
249
+ loc := sort .Search (len (s .members ), func (i int ) bool {
250
+ return ! s .members [i ].Less (pe )
251
+ })
252
+ if loc == len (s .members ) {
160
253
return false
161
254
}
162
- _ , ok := s .members [pe .String ()]
163
- return ok
255
+ if s .members [loc ].Equals (pe ) {
256
+ return true
257
+ }
258
+ return false
164
259
}
165
260
166
261
// Equals returns true if s and s2 have exactly the same members.
@@ -169,14 +264,14 @@ func (s *PathElementSet) Equals(s2 *PathElementSet) bool {
169
264
return false
170
265
}
171
266
for k := range s .members {
172
- if _ , ok := s2 .members [k ]; ! ok {
267
+ if ! s . members [ k ]. Equals ( s2 .members [k ]) {
173
268
return false
174
269
}
175
270
}
176
271
return true
177
272
}
178
273
179
- // Iterate calls f for each PathElement in the set.
274
+ // Iterate calls f for each PathElement in the set. The order is deterministic.
180
275
func (s * PathElementSet ) Iterate (f func (PathElement )) {
181
276
for _ , pe := range s .members {
182
277
f (pe )
0 commit comments