mirror of
https://github.com/tailscale/tailscale.git
synced 2025-03-29 20:42:22 +00:00
types/views: add SliceEqualAnyOrderFunc
Extracted from some code written in the other repo. Updates tailscale/corp#25479 Signed-off-by: Andrew Dunham <andrew@du.nham.ca> Change-Id: I6df062fdffa1705524caa44ac3b6f2788cf64595
This commit is contained in:
parent
a51672cafd
commit
7fa07f3416
@ -360,6 +360,41 @@ func SliceEqualAnyOrder[T comparable](a, b Slice[T]) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// SliceEqualAnyOrderFunc reports whether a and b contain the same elements,
|
||||
// regardless of order. The underlying slices for a and b can be nil.
|
||||
//
|
||||
// The provided function should return a comparable value for each element.
|
||||
func SliceEqualAnyOrderFunc[T any, V comparable](a, b Slice[T], cmp func(T) V) bool {
|
||||
if a.Len() != b.Len() {
|
||||
return false
|
||||
}
|
||||
|
||||
var diffStart int // beginning index where a and b differ
|
||||
for n := a.Len(); diffStart < n; diffStart++ {
|
||||
av := cmp(a.At(diffStart))
|
||||
bv := cmp(b.At(diffStart))
|
||||
if av != bv {
|
||||
break
|
||||
}
|
||||
}
|
||||
if diffStart == a.Len() {
|
||||
return true
|
||||
}
|
||||
|
||||
// count the occurrences of remaining values and compare
|
||||
valueCount := make(map[V]int)
|
||||
for i, n := diffStart, a.Len(); i < n; i++ {
|
||||
valueCount[cmp(a.At(i))]++
|
||||
valueCount[cmp(b.At(i))]--
|
||||
}
|
||||
for _, count := range valueCount {
|
||||
if count != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// MapSlice is a view over a map whose values are slices.
|
||||
type MapSlice[K comparable, V any] struct {
|
||||
// ж is the underlying mutable value, named with a hard-to-type
|
||||
|
@ -153,6 +153,43 @@ func TestViewUtils(t *testing.T) {
|
||||
qt.Equals, true)
|
||||
}
|
||||
|
||||
func TestSliceEqualAnyOrderFunc(t *testing.T) {
|
||||
type nc struct {
|
||||
_ structs.Incomparable
|
||||
v string
|
||||
}
|
||||
|
||||
// ncFrom returns a Slice[nc] from a slice of []string
|
||||
ncFrom := func(s ...string) Slice[nc] {
|
||||
var out []nc
|
||||
for _, v := range s {
|
||||
out = append(out, nc{v: v})
|
||||
}
|
||||
return SliceOf(out)
|
||||
}
|
||||
|
||||
// cmp returns a comparable value for a nc
|
||||
cmp := func(a nc) string { return a.v }
|
||||
|
||||
v := ncFrom("foo", "bar")
|
||||
c := qt.New(t)
|
||||
|
||||
// Simple case of slice equal to itself.
|
||||
c.Check(SliceEqualAnyOrderFunc(v, v, cmp), qt.Equals, true)
|
||||
|
||||
// Different order.
|
||||
c.Check(SliceEqualAnyOrderFunc(v, ncFrom("bar", "foo"), cmp), qt.Equals, true)
|
||||
|
||||
// Different values, same length
|
||||
c.Check(SliceEqualAnyOrderFunc(v, ncFrom("foo", "baz"), cmp), qt.Equals, false)
|
||||
|
||||
// Different values, different length
|
||||
c.Check(SliceEqualAnyOrderFunc(v, ncFrom("foo"), cmp), qt.Equals, false)
|
||||
|
||||
// Nothing shared
|
||||
c.Check(SliceEqualAnyOrderFunc(v, ncFrom("baz", "qux"), cmp), qt.Equals, false)
|
||||
}
|
||||
|
||||
func TestSliceEqual(t *testing.T) {
|
||||
a := SliceOf([]string{"foo", "bar"})
|
||||
b := SliceOf([]string{"foo", "bar"})
|
||||
|
Loading…
x
Reference in New Issue
Block a user