util/deephash: move typeIsRecursive and canMemHash to types.go (#5386)

Also, rename canMemHash to typeIsMemHashable to be consistent.
There are zero changes to the semantics.

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This commit is contained in:
Joe Tsai
2022-08-16 09:31:19 -07:00
committed by GitHub
parent d53eb6fa11
commit 44d62b65d0
4 changed files with 206 additions and 188 deletions

View File

@@ -10,7 +10,6 @@ import (
"encoding/binary"
"fmt"
"hash"
"io"
"math"
"math/rand"
"net/netip"
@@ -19,14 +18,12 @@ import (
"testing"
"testing/quick"
"time"
"unsafe"
"go4.org/mem"
"tailscale.com/tailcfg"
"tailscale.com/types/dnstype"
"tailscale.com/types/ipproto"
"tailscale.com/types/key"
"tailscale.com/types/structs"
"tailscale.com/util/deephash/testtype"
"tailscale.com/util/dnsname"
"tailscale.com/version"
@@ -289,41 +286,6 @@ func getVal() any {
}
}
func TestTypeIsRecursive(t *testing.T) {
type RecursiveStruct struct {
v *RecursiveStruct
}
type RecursiveChan chan *RecursiveChan
tests := []struct {
val any
want bool
}{
{val: 42, want: false},
{val: "string", want: false},
{val: 1 + 2i, want: false},
{val: struct{}{}, want: false},
{val: (*RecursiveStruct)(nil), want: true},
{val: RecursiveStruct{}, want: true},
{val: time.Unix(0, 0), want: false},
{val: structs.Incomparable{}, want: false}, // ignore its [0]func()
{val: tailcfg.NetPortRange{}, want: false}, // uses structs.Incomparable
{val: (*tailcfg.Node)(nil), want: false},
{val: map[string]bool{}, want: false},
{val: func() {}, want: false},
{val: make(chan int), want: false},
{val: unsafe.Pointer(nil), want: false},
{val: make(RecursiveChan), want: true},
{val: make(chan int), want: false},
}
for _, tt := range tests {
got := typeIsRecursive(reflect.TypeOf(tt.val))
if got != tt.want {
t.Errorf("for type %T: got %v, want %v", tt.val, got, tt.want)
}
}
}
type IntThenByte struct {
i int
b byte
@@ -337,68 +299,6 @@ type IntIntByteInt struct {
i3 int32
}
func TestCanMemHash(t *testing.T) {
tests := []struct {
val any
want bool
}{
{true, true},
{uint(1), true},
{uint8(1), true},
{uint16(1), true},
{uint32(1), true},
{uint64(1), true},
{uintptr(1), true},
{int(1), true},
{int8(1), true},
{int16(1), true},
{int32(1), true},
{int64(1), true},
{float32(1), true},
{float64(1), true},
{complex64(1), true},
{complex128(1), true},
{[32]byte{}, true},
{func() {}, false},
{make(chan int), false},
{struct{ io.Writer }{nil}, false},
{unsafe.Pointer(nil), false},
{new(int), false},
{TwoInts{}, true},
{[4]TwoInts{}, true},
{IntThenByte{}, false},
{[4]IntThenByte{}, false},
{tailcfg.PortRange{}, true},
{int16(0), true},
{struct {
_ int
_ int
}{}, true},
{struct {
_ int
_ uint8
_ int
}{}, false}, // gap
{struct {
_ structs.Incomparable // if not last, zero-width
x int
}{}, true},
{struct {
x int
_ structs.Incomparable // zero-width last: has space, can't memhash
}{},
false},
{[0]chan bool{}, true},
{struct{ f [0]func() }{}, true},
}
for _, tt := range tests {
got := canMemHash(reflect.TypeOf(tt.val))
if got != tt.want {
t.Errorf("for type %T: got %v, want %v", tt.val, got, tt.want)
}
}
}
func u8(n uint8) string { return string([]byte{n}) }
func u16(n uint16) string { return string(binary.LittleEndian.AppendUint16(nil, n)) }
func u32(n uint32) string { return string(binary.LittleEndian.AppendUint32(nil, n)) }