Skip to content

Commit 6ddeae7

Browse files
committed
types/views: optimize SliceEqualAnyOrderFunc for small slices
If the total number of differences is less than a small amount, just do the dumb quadratic thing and compare every single object instead of allocating a map. Updates tailscale/corp#25479 Signed-off-by: Andrew Dunham <[email protected]> Change-Id: I8931b4355a2da4ec0f19739927311cf88711a840
1 parent 7fa07f3 commit 6ddeae7

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

types/views/views.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,29 @@ func SliceEqualAnyOrderFunc[T any, V comparable](a, b Slice[T], cmp func(T) V) b
381381
return true
382382
}
383383

384+
// For a small number of items, avoid the allocation of a map and just
385+
// do the quadratic thing. We can also only check the items between
386+
// diffStart and the end.
387+
nRemain := a.Len() - diffStart
388+
if nRemain <= 5 {
389+
maxLen := a.Len() // same as b.Len()
390+
for i := diffStart; i < maxLen; i++ {
391+
av := cmp(a.At(i))
392+
found := false
393+
for j := diffStart; j < maxLen; j++ {
394+
bv := cmp(b.At(j))
395+
if av == bv {
396+
found = true
397+
break
398+
}
399+
}
400+
if !found {
401+
return false
402+
}
403+
}
404+
return true
405+
}
406+
384407
// count the occurrences of remaining values and compare
385408
valueCount := make(map[V]int)
386409
for i, n := diffStart, a.Len(); i < n; i++ {

types/views/views_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,15 @@ func TestSliceEqualAnyOrderFunc(t *testing.T) {
188188

189189
// Nothing shared
190190
c.Check(SliceEqualAnyOrderFunc(v, ncFrom("baz", "qux"), cmp), qt.Equals, false)
191+
192+
// Long slice that matches
193+
longSlice := ncFrom("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")
194+
longSame := ncFrom("b", "a", "c", "d", "e", "f", "g", "h", "i", "j") // first 2 elems swapped
195+
c.Check(SliceEqualAnyOrderFunc(longSlice, longSame, cmp), qt.Equals, true)
196+
197+
// Long difference; past the quadratic limit
198+
longDiff := ncFrom("b", "a", "c", "d", "e", "f", "g", "h", "i", "k") // differs at end
199+
c.Check(SliceEqualAnyOrderFunc(longSlice, longDiff, cmp), qt.Equals, false)
191200
}
192201

193202
func TestSliceEqual(t *testing.T) {

0 commit comments

Comments
 (0)