Skip to content

Commit 5974892

Browse files
committed
remove more maps (and String() calls) to reduce allocations further
1 parent ea08d7c commit 5974892

File tree

3 files changed

+120
-64
lines changed

3 files changed

+120
-64
lines changed

fieldpath/element.go

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,8 @@ type PathElement struct {
4747
Index *int
4848
}
4949

50-
// less provides an order for path elements.
51-
func (e PathElement) less(rhs PathElement) bool {
52-
// For testing the concept, just use the existing string.
53-
//return e.String() < rhs.String()
50+
// Less provides an order for path elements.
51+
func (e PathElement) Less(rhs PathElement) bool {
5452
if e.FieldName != nil {
5553
if rhs.FieldName == nil {
5654
return true
@@ -94,7 +92,7 @@ func (e PathElement) less(rhs PathElement) bool {
9492

9593
// Equal returns true if both path elements are equal.
9694
func (e PathElement) Equal(rhs PathElement) bool {
97-
return !e.less(rhs) && !rhs.less(e)
95+
return !e.Less(rhs) && !rhs.Less(e)
9896
}
9997

10098
// String presents the path element as a human-readable string.
@@ -142,22 +140,19 @@ func KeyByFields(nameValues ...interface{}) []value.Field {
142140
// PathElementSet is a set of path elements.
143141
// TODO: serialize as a list.
144142
type PathElementSet struct {
145-
// The strange construction is because there's no way to test
146-
// PathElements for equality (it can't be used as a key for a map).
147143
members sortedPathElements
148144
}
149145

150146
type sortedPathElements []PathElement
151147

152148
func (spe sortedPathElements) Len() int { return len(spe) }
153-
func (spe sortedPathElements) Less(i, j int) bool { return spe[i].less(spe[j]) }
149+
func (spe sortedPathElements) Less(i, j int) bool { return spe[i].Less(spe[j]) }
154150
func (spe sortedPathElements) Swap(i, j int) { spe[i], spe[j] = spe[j], spe[i] }
155151

156152
// Insert adds pe to the set.
157153
func (s *PathElementSet) Insert(pe PathElement) {
158154
loc := sort.Search(len(s.members), func(i int) bool {
159-
//return !pe.less(s.members[i])
160-
return !s.members[i].less(pe)
155+
return !s.members[i].Less(pe)
161156
})
162157
if loc == len(s.members) {
163158
s.members = append(s.members, pe)
@@ -181,12 +176,12 @@ func (s *PathElementSet) Union(s2 *PathElementSet) *PathElementSet {
181176

182177
i, j := 0, 0
183178
for i < len(s.members) && j < len(s2.members) {
184-
if s.members[i].less(s2.members[j]) {
179+
if s.members[i].Less(s2.members[j]) {
185180
out.members = append(out.members, s.members[i])
186181
i++
187182
} else {
188183
out.members = append(out.members, s2.members[j])
189-
if !s2.members[j].less(s.members[i]) {
184+
if !s2.members[j].Less(s.members[i]) {
190185
i++
191186
}
192187
j++
@@ -208,10 +203,10 @@ func (s *PathElementSet) Intersection(s2 *PathElementSet) *PathElementSet {
208203

209204
i, j := 0, 0
210205
for i < len(s.members) && j < len(s2.members) {
211-
if s.members[i].less(s2.members[j]) {
206+
if s.members[i].Less(s2.members[j]) {
212207
i++
213208
} else {
214-
if !s2.members[j].less(s.members[i]) {
209+
if !s2.members[j].Less(s.members[i]) {
215210
out.members = append(out.members, s.members[i])
216211
i++
217212
}
@@ -228,11 +223,11 @@ func (s *PathElementSet) Difference(s2 *PathElementSet) *PathElementSet {
228223

229224
i, j := 0, 0
230225
for i < len(s.members) && j < len(s2.members) {
231-
if s.members[i].less(s2.members[j]) {
226+
if s.members[i].Less(s2.members[j]) {
232227
out.members = append(out.members, s.members[i])
233228
i++
234229
} else {
235-
if !s2.members[j].less(s.members[i]) {
230+
if !s2.members[j].Less(s.members[i]) {
236231
i++
237232
}
238233
j++
@@ -250,8 +245,7 @@ func (s *PathElementSet) Size() int { return len(s.members) }
250245
// Has returns true if pe is a member of the set.
251246
func (s *PathElementSet) Has(pe PathElement) bool {
252247
loc := sort.Search(len(s.members), func(i int) bool {
253-
return !s.members[i].less(pe)
254-
//return !pe.less(s.members[i])
248+
return !s.members[i].Less(pe)
255249
})
256250
if loc == len(s.members) {
257251
return false

fieldpath/path.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,35 @@ func (fp Path) String() string {
3535
return strings.Join(strs, "")
3636
}
3737

38+
// Less provides a lexical order for Paths.
39+
func (fp Path) Less(rhs Path) bool {
40+
i := 0
41+
for {
42+
if i >= len(fp) && i >= len(rhs) {
43+
// Paths are the same length and all items are equal.
44+
return false
45+
}
46+
if i >= len(fp) {
47+
// LHS is shorter.
48+
return true
49+
}
50+
if i >= len(rhs) {
51+
// RHS is shorter.
52+
return false
53+
}
54+
if fp[i].Less(rhs[i]) {
55+
// LHS is less; return
56+
return true
57+
}
58+
if rhs[i].Less(fp[i]) {
59+
// RHS is less; return
60+
return false
61+
}
62+
// The items are equal; continue.
63+
i++
64+
}
65+
}
66+
3867
func (fp Path) Copy() Path {
3968
new := make(Path, len(fp))
4069
copy(new, fp)

fieldpath/set.go

Lines changed: 79 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package fieldpath
1818

1919
import (
20+
"sort"
2021
"strings"
2122
)
2223

@@ -172,24 +173,29 @@ type setNode struct {
172173

173174
// SetNodeMap is a map of PathElement to subset.
174175
type SetNodeMap struct {
175-
members map[string]setNode
176+
members []setNode
176177
}
177178

178179
// Descend adds pe to the set if necessary, returning the associated subset.
179180
func (s *SetNodeMap) Descend(pe PathElement) *Set {
180-
serialized := pe.String()
181-
if s.members == nil {
182-
s.members = map[string]setNode{}
181+
loc := sort.Search(len(s.members), func(i int) bool {
182+
return !s.members[i].pathElement.Less(pe)
183+
})
184+
if loc == len(s.members) {
185+
s.members = append(s.members, setNode{pathElement: pe, set: &Set{}})
186+
return s.members[loc].set
183187
}
184-
if n, ok := s.members[serialized]; ok {
185-
return n.set
188+
if s.members[loc].pathElement.Equal(pe) {
189+
return s.members[loc].set
186190
}
187-
ss := &Set{}
188-
s.members[serialized] = setNode{
189-
pathElement: pe,
190-
set: ss,
191+
n := len(s.members) - 1
192+
s.members = append(s.members, s.members[n])
193+
for n > loc {
194+
s.members[n] = s.members[n-1]
195+
n--
191196
}
192-
return ss
197+
s.members[loc] = setNode{pathElement: pe, set: &Set{}}
198+
return s.members[loc].set
193199
}
194200

195201
// Size returns the sum of the number of members of all subsets.
@@ -213,12 +219,14 @@ func (s *SetNodeMap) Empty() bool {
213219

214220
// Get returns (the associated set, true) or (nil, false) if there is none.
215221
func (s *SetNodeMap) Get(pe PathElement) (*Set, bool) {
216-
if s.members == nil {
222+
loc := sort.Search(len(s.members), func(i int) bool {
223+
return !s.members[i].pathElement.Less(pe)
224+
})
225+
if loc == len(s.members) {
217226
return nil, false
218227
}
219-
serialized := pe.String()
220-
if n, ok := s.members[serialized]; ok {
221-
return n.set, true
228+
if s.members[loc].pathElement.Equal(pe) {
229+
return s.members[loc].set, true
222230
}
223231
return nil, false
224232
}
@@ -229,12 +237,11 @@ func (s *SetNodeMap) Equals(s2 *SetNodeMap) bool {
229237
if len(s.members) != len(s2.members) {
230238
return false
231239
}
232-
for k, v := range s.members {
233-
v2, ok := s2.members[k]
234-
if !ok {
240+
for i := range s.members {
241+
if !s.members[i].pathElement.Equal(s2.members[i].pathElement) {
235242
return false
236243
}
237-
if !v.set.Equals(v2.set) {
244+
if !s.members[i].set.Equals(s2.members[i].set) {
238245
return false
239246
}
240247
}
@@ -244,35 +251,49 @@ func (s *SetNodeMap) Equals(s2 *SetNodeMap) bool {
244251
// Union returns a SetNodeMap with members that appear in either s or s2.
245252
func (s *SetNodeMap) Union(s2 *SetNodeMap) *SetNodeMap {
246253
out := &SetNodeMap{}
247-
for k, sn := range s.members {
248-
pe := sn.pathElement
249-
if sn2, ok := s2.members[k]; ok {
250-
*out.Descend(pe) = *sn.set.Union(sn2.set)
254+
255+
i, j := 0, 0
256+
for i < len(s.members) && j < len(s2.members) {
257+
if s.members[i].pathElement.Less(s2.members[j].pathElement) {
258+
out.members = append(out.members, s.members[i])
259+
i++
251260
} else {
252-
*out.Descend(pe) = *sn.set
261+
if !s2.members[j].pathElement.Less(s.members[i].pathElement) {
262+
out.members = append(out.members, setNode{pathElement: s.members[i].pathElement, set: s.members[i].set.Union(s2.members[j].set)})
263+
i++
264+
} else {
265+
out.members = append(out.members, s2.members[j])
266+
}
267+
j++
253268
}
254269
}
255-
for k, sn2 := range s2.members {
256-
pe := sn2.pathElement
257-
if _, ok := s.members[k]; ok {
258-
// already handled
259-
continue
260-
}
261-
*out.Descend(pe) = *sn2.set
270+
271+
if i < len(s.members) {
272+
out.members = append(out.members, s.members[i:]...)
273+
}
274+
if j < len(s2.members) {
275+
out.members = append(out.members, s2.members[j:]...)
262276
}
263277
return out
264278
}
265279

266280
// Intersection returns a SetNodeMap with members that appear in both s and s2.
267281
func (s *SetNodeMap) Intersection(s2 *SetNodeMap) *SetNodeMap {
268282
out := &SetNodeMap{}
269-
for k, sn := range s.members {
270-
pe := sn.pathElement
271-
if sn2, ok := s2.members[k]; ok {
272-
i := *sn.set.Intersection(sn2.set)
273-
if !i.Empty() {
274-
*out.Descend(pe) = i
283+
284+
i, j := 0, 0
285+
for i < len(s.members) && j < len(s2.members) {
286+
if s.members[i].pathElement.Less(s2.members[j].pathElement) {
287+
i++
288+
} else {
289+
if !s2.members[j].pathElement.Less(s.members[i].pathElement) {
290+
res := s.members[i].set.Intersection(s2.members[j].set)
291+
if !res.Empty() {
292+
out.members = append(out.members, setNode{pathElement: s.members[i].pathElement, set: res})
293+
}
294+
i++
275295
}
296+
j++
276297
}
277298
}
278299
return out
@@ -281,18 +302,30 @@ func (s *SetNodeMap) Intersection(s2 *SetNodeMap) *SetNodeMap {
281302
// Difference returns a SetNodeMap with members that appear in s but not in s2.
282303
func (s *SetNodeMap) Difference(s2 *Set) *SetNodeMap {
283304
out := &SetNodeMap{}
284-
for k, sn := range s.members {
285-
pe := sn.pathElement
286-
if sn2, ok := s2.Children.members[k]; ok {
287-
diff := *sn.set.Difference(sn2.set)
288-
// We aren't permitted to add nodes with no elements.
289-
if !diff.Empty() {
290-
*out.Descend(pe) = diff
291-
}
305+
306+
i, j := 0, 0
307+
for i < len(s.members) && j < len(s2.Children.members) {
308+
if s.members[i].pathElement.Less(s2.Children.members[j].pathElement) {
309+
out.members = append(out.members, setNode{pathElement: s.members[i].pathElement, set: s.members[i].set})
310+
i++
292311
} else {
293-
*out.Descend(pe) = *sn.set
312+
if !s2.Children.members[j].pathElement.Less(s.members[i].pathElement) {
313+
314+
diff := s.members[i].set.Difference(s2.Children.members[j].set)
315+
// We aren't permitted to add nodes with no elements.
316+
if !diff.Empty() {
317+
out.members = append(out.members, setNode{pathElement: s.members[i].pathElement, set: diff})
318+
}
319+
320+
i++
321+
}
322+
j++
294323
}
295324
}
325+
326+
if i < len(s.members) {
327+
out.members = append(out.members, s.members[i:]...)
328+
}
296329
return out
297330
}
298331

0 commit comments

Comments
 (0)