Change-Id: Ic392ffab19c02982c8676f274932ba0d61cc54da
This commit is contained in:
qiulaidongfeng 2024-08-31 09:49:52 +08:00
parent 02df413842
commit 76684949a2
4 changed files with 75 additions and 47 deletions

View File

@ -286,7 +286,7 @@ func (h *Hash) BlockSize() int { return len(h.buf) }
// If v contains a floating-point NaN, then the hash is non-deterministically random.
func Comparable[T comparable](seed Seed, v T) uint64 {
abi.Escape(v)
t := abi.TypeOf(v)
t := abi.TypeFor[T]()
len := t.Size()
if len == 0 {
return seed.s
@ -297,7 +297,7 @@ func Comparable[T comparable](seed Seed, v T) uint64 {
// WriteComparable adds x to the data hashed by h.
func WriteComparable[T comparable](h *Hash, x T) {
v := Comparable(h.seed, x)
var buf []byte
var buf [8]byte
byteorder.LePutUint64(buf[:], v)
h.Write(buf[:])
}

View File

@ -95,17 +95,12 @@ func mix(a, b uint64) uint64 {
return hi ^ lo
}
var byteSliceTyp = reflect.TypeFor[[]byte]()
var strSliceTyp = reflect.TypeFor[string]()
var strTyp = reflect.TypeFor[string]()
func comparableF[T comparable](seed uint64, v T, t *abi.Type) uint64 {
vv := reflect.ValueOf(v)
typ := vv.Type()
if typ == byteSliceTyp {
return wyhash(vv.Bytes(), seed, uint64(vv.Len()))
}
if typ == strSliceTyp {
if typ == strTyp {
return rthashString(vv.String(), seed)
}
buf := make([]byte, 0, typ.Size())
@ -119,7 +114,7 @@ func appendT(buf []byte, v reflect.Value) []byte {
return byteorder.LeAppendUint64(buf, uint64(v.Int()))
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr:
return byteorder.LeAppendUint64(buf, v.Uint())
case reflect.Array, reflect.Slice:
case reflect.Array:
for i := range v.Len() {
buf = appendT(buf, v.Index(i))
}
@ -142,6 +137,8 @@ func appendT(buf []byte, v reflect.Value) []byte {
case reflect.UnsafePointer, reflect.Pointer:
return byteorder.LeAppendUint64(buf, uint64(v.Pointer()))
case reflect.Interface:
// There is no need to check comparability here,
// because !purego also treats it as a piece of memory.
a := v.InterfaceData()
buf = byteorder.LeAppendUint64(buf, uint64(a[0]))
return byteorder.LeAppendUint64(buf, uint64(a[1]))

View File

@ -48,11 +48,7 @@ func comparableF[T comparable](seed uint64, v T, t *abi.Type) uint64 {
k := t.Kind()
len := t.Size()
ptr := unsafe.Pointer(&v)
switch k {
case abi.Slice:
len = uintptr(((*unsafeheader.Slice)(unsafe.Pointer(&v))).Len) * t.Elem().Size()
ptr = ((*unsafeheader.Slice)(unsafe.Pointer(&v))).Data
case abi.String:
if k == abi.String {
len = uintptr(((*unsafeheader.String)(unsafe.Pointer(&v))).Len)
ptr = ((*unsafeheader.String)(unsafe.Pointer(&v))).Data
}

View File

@ -8,6 +8,7 @@ import (
"bytes"
"fmt"
"hash"
"reflect"
"testing"
)
@ -210,19 +211,36 @@ func TestSeedFromReset(t *testing.T) {
}
}
func TestCompare(t *testing.T) {
var a, b int = 2, 2
var pa *int = &a
seed := MakeSeed()
if Comparable(seed, a) != Comparable(seed, b) {
t.Fatal("Comparable(seed, 2) != Comparable(seed, 2)")
}
old := Comparable(seed, pa)
stackGrow(8192)
new := Comparable(seed, pa)
if old != new {
t.Fatal("Comparable(seed, ptr) != Comparable(seed, ptr)")
}
func TestComparable(t *testing.T) {
testComparable(t, int64(2))
testComparable(t, uint64(8))
testComparable(t, uintptr(12))
testComparable(t, any("s"))
testComparable(t, "s")
testComparable(t, new(float64))
testComparable(t, float64(9))
testComparable(t, complex128(9i+1))
testComparable(t, struct {
i int
f float64
}{i: 9, f: 9.9})
}
func testComparable[T comparable](t *testing.T, v T) {
t.Run(reflect.TypeFor[T]().Name(), func(t *testing.T) {
var a, b T = v, v
var pa *T = &a
seed := MakeSeed()
if Comparable(seed, a) != Comparable(seed, b) {
t.Fatalf("Comparable(seed, %v) != Comparable(seed, %v)", a, b)
}
old := Comparable(seed, pa)
stackGrow(8192)
new := Comparable(seed, pa)
if old != new {
t.Fatal("Comparable(seed, ptr) != Comparable(seed, ptr)")
}
})
}
//go:noinline
@ -236,25 +254,42 @@ func stackGrow(dep int) {
}
func TestWriteComparable(t *testing.T) {
var a, b int = 2, 2
var pa *int = &a
h1 := Hash{}
h2 := Hash{}
h1.seed = MakeSeed()
h2.seed = h1.seed
WriteComparable(&h1, a)
WriteComparable(&h2, b)
if h1.Sum64() != h1.Sum64() {
t.Fatal("WriteComparable(h, 2) != WriteComparable(h, 2)")
}
WriteComparable(&h1, pa)
old := h1.Sum64()
stackGrow(8192)
WriteComparable(&h2, pa)
new := h2.Sum64()
if old != new {
t.Fatal("WriteComparable(seed, ptr) != WriteComparable(seed, ptr)")
}
testWriteComparable(t, int64(2))
testWriteComparable(t, uint64(8))
testWriteComparable(t, uintptr(12))
testWriteComparable(t, any("s"))
testWriteComparable(t, "s")
testWriteComparable(t, new(float64))
testWriteComparable(t, float64(9))
testWriteComparable(t, complex128(9i+1))
testWriteComparable(t, struct {
i int
f float64
}{i: 9, f: 9.9})
}
func testWriteComparable[T comparable](t *testing.T, v T) {
t.Run(reflect.TypeFor[T]().Name(), func(t *testing.T) {
var a, b T = v, v
var pa *T = &a
h1 := Hash{}
h2 := Hash{}
h1.seed = MakeSeed()
h2.seed = h1.seed
WriteComparable(&h1, a)
WriteComparable(&h2, b)
if h1.Sum64() != h1.Sum64() {
t.Fatalf("WriteComparable(h, %v) != WriteComparable(h, %v)", a, b)
}
WriteComparable(&h1, pa)
old := h1.Sum64()
stackGrow(8192)
WriteComparable(&h2, pa)
new := h2.Sum64()
if old != new {
t.Fatal("WriteComparable(seed, ptr) != WriteComparable(seed, ptr)")
}
})
}
// Make sure a Hash implements the hash.Hash and hash.Hash64 interfaces.