Change-Id: I9107ab7d0cbb6e05b6c87951cb143ce6a2e67b01
This commit is contained in:
qiulaidongfeng 2024-09-10 20:24:29 +08:00
parent c93aab36ac
commit 88e331099d
4 changed files with 73 additions and 43 deletions

View File

@ -359,26 +359,11 @@ func appendT(h *Hash, v reflect.Value) {
return
case reflect.Complex64, reflect.Complex128:
c := v.Complex()
var buf [8]byte
byteorder.LePutUint64(buf[:], math.Float64bits(real(c)))
h.Write(buf[:])
byteorder.LePutUint64(buf[:], math.Float64bits(imag(c)))
h.Write(buf[:])
h.float64(real(c))
h.float64(imag(c))
return
case reflect.Float32, reflect.Float64:
f := v.Float()
if f == 0 {
h.WriteByte(0)
return
}
var buf [8]byte
if f != f {
byteorder.LePutUint64(buf[:], randUint64())
h.Write(buf[:])
return
}
byteorder.LePutUint64(buf[:], math.Float64bits(f))
h.Write(buf[:])
h.float64(v.Float())
return
case reflect.Bool:
h.WriteByte(btoi(v.Bool()))
@ -395,6 +380,22 @@ func appendT(h *Hash, v reflect.Value) {
panic(fmt.Errorf("hash/maphash: %s not comparable", v.Type().String()))
}
func (h *Hash) float64(f float64) {
if f == 0 {
h.WriteByte(0)
return
}
var buf [8]byte
if f != f {
byteorder.LePutUint64(buf[:], randUint64())
h.Write(buf[:])
return
}
byteorder.LePutUint64(buf[:], math.Float64bits(f))
h.Write(buf[:])
return
}
func btoi(b bool) byte {
if b {
return 1

View File

@ -94,8 +94,6 @@ func mix(a, b uint64) uint64 {
return hi ^ lo
}
var strTyp = reflect.TypeFor[string]()
func comparableF[T comparable](h *Hash, v T) {
vv := reflect.ValueOf(v)
appendT(h, vv)

View File

@ -48,21 +48,15 @@ func comparableF[T comparable](h *Hash, v T) {
t := abi.TypeFor[T]()
ptr := unsafe.Pointer(&v)
l := t.Size()
k := t.Kind()
if k == abi.String {
s := ((*string)(ptr))
h.WriteString(*s)
if t.TFlag&abi.TFlagRegularMemory != 0 {
h.Write(unsafe.Slice((*byte)(ptr), l))
return
}
if t.TFlag&abi.TFlagRegularMemory == 0 {
// Note: if T like struct {s string}
// str value equal but ptr not equal,
// if think of it as a contiguous piece of memory,
// hash it, that happen v1 == v2
// Comparable(s, v1) != Comparable(s, v2).
vv := reflect.ValueOf(v)
appendT(h, vv)
return
}
h.Write(unsafe.Slice((*byte)(ptr), l))
// Note: if T like struct {s string}
// str value equal but ptr not equal,
// if think of it as a contiguous piece of memory,
// hash it, that happen v1 == v2
// Comparable(s, v1) != Comparable(s, v2).
vv := reflect.ValueOf(v)
appendT(h, vv)
}

View File

@ -227,13 +227,19 @@ func TestComparable(t *testing.T) {
testComparable(t, uintptr(12))
testComparable(t, any("s"))
testComparable(t, "s")
testComparable(t, true)
testComparable(t, new(float64))
testComparable(t, float64(9))
testComparable(t, complex128(9i+1))
testComparable(t, struct{}{})
testComparable(t, struct {
i int
u uint
b bool
f float64
}{i: 9, f: 9.9})
p *int
a any
}{i: 9, u: 1, b: true, f: 9.9, p: new(int), a: 1})
type S struct {
s string
}
@ -246,11 +252,21 @@ func TestComparable(t *testing.T) {
t.Fatalf("unexpected two heapStr value not equal")
}
testComparable(t, s1, s2)
testComparable(t, s1.s, s2.s)
testComparable(t, float32(0), negativeZero[float32]())
testComparable(t, float64(0), negativeZero[float64]())
testComparableNoEqual(t, math.NaN(), math.NaN())
testComparableNoEqual(t, [2]string{"a", ""}, [2]string{"", "a"})
testComparableNoEqual(t, any(struct{ x int }{x: 1}), any(struct {
x int
s string
}{x: 1}))
}
func testComparableNoEqual[T comparable](t *testing.T, v1, v2 T) {
seed := MakeSeed()
if Comparable(seed, math.NaN()) == Comparable(seed, math.NaN()) {
t.Fatalf("Comparable(seed, NaN) == Comparable(seed, NaN)")
if Comparable(seed, v1) == Comparable(seed, v2) {
t.Fatalf("Comparable(seed, %v) == Comparable(seed, %v)", v1, v2)
}
}
@ -291,13 +307,17 @@ func testComparable[T comparable](t *testing.T, v T, v2 ...T) {
})
}
var use byte
//go:noinline
func stackGrow(dep int) {
if dep == 0 {
return
}
var local [1024]byte
_ = local
// make sure local is allocated on the stack.
local[randUint64()%1024] = byte(randUint64())
use = local[randUint64()%1024]
stackGrow(dep - 1)
}
@ -307,13 +327,19 @@ func TestWriteComparable(t *testing.T) {
testWriteComparable(t, uintptr(12))
testWriteComparable(t, any("s"))
testWriteComparable(t, "s")
testComparable(t, true)
testWriteComparable(t, new(float64))
testWriteComparable(t, float64(9))
testWriteComparable(t, complex128(9i+1))
testWriteComparable(t, struct{}{})
testWriteComparable(t, struct {
i int
u uint
b bool
f float64
}{i: 9, f: 9.9})
p *int
a any
}{i: 9, u: 1, b: true, f: 9.9, p: new(int), a: 1})
type S struct {
s string
}
@ -326,17 +352,28 @@ func TestWriteComparable(t *testing.T) {
t.Fatalf("unexpected two heapStr value not equal")
}
testWriteComparable(t, s1, s2)
testWriteComparable(t, s1.s, s2.s)
testWriteComparable(t, float32(0), negativeZero[float32]())
testWriteComparable(t, float64(0), negativeZero[float64]())
testWriteComparableNoEqual(t, math.NaN(), math.NaN())
testWriteComparableNoEqual(t, [2]string{"a", ""}, [2]string{"", "a"})
testWriteComparableNoEqual(t, any(struct{ x int }{x: 1}), any(struct {
x int
s string
}{x: 1}))
}
func testWriteComparableNoEqual[T comparable](t *testing.T, v1, v2 T) {
seed := MakeSeed()
h1 := Hash{}
h2 := Hash{}
h1.seed, h2.seed = seed, seed
WriteComparable(&h1, math.NaN())
WriteComparable(&h2, math.NaN())
WriteComparable(&h1, v1)
WriteComparable(&h2, v2)
if h1.Sum64() == h2.Sum64() {
t.Fatalf("WriteComparable(seed, NaN) == WriteComparable(seed, NaN)")
t.Fatalf("WriteComparable(seed, %v) == WriteComparable(seed, %v)", v1, v2)
}
}
func testWriteComparable[T comparable](t *testing.T, v T, v2 ...T) {