package runtime
import (
"internal/abi"
"internal/cpu"
"internal/goarch"
"unsafe"
)
const (
c0 = uintptr ((8 -goarch .PtrSize )/4 *2860486313 + (goarch .PtrSize -4 )/4 *33054211828000289 )
c1 = uintptr ((8 -goarch .PtrSize )/4 *3267000013 + (goarch .PtrSize -4 )/4 *23344194077549503 )
)
func memhash0 (p unsafe .Pointer , h uintptr ) uintptr {
return h
}
func memhash8 (p unsafe .Pointer , h uintptr ) uintptr {
return memhash (p , h , 1 )
}
func memhash16 (p unsafe .Pointer , h uintptr ) uintptr {
return memhash (p , h , 2 )
}
func memhash128 (p unsafe .Pointer , h uintptr ) uintptr {
return memhash (p , h , 16 )
}
func memhash_varlen (p unsafe .Pointer , h uintptr ) uintptr {
ptr := getclosureptr ()
size := *(*uintptr )(unsafe .Pointer (ptr + unsafe .Sizeof (h )))
return memhash (p , h , size )
}
var useAeshash bool
func memhash (p unsafe .Pointer , h , s uintptr ) uintptr
func memhash32 (p unsafe .Pointer , h uintptr ) uintptr
func memhash64 (p unsafe .Pointer , h uintptr ) uintptr
func strhash (p unsafe .Pointer , h uintptr ) uintptr
func strhashFallback (a unsafe .Pointer , h uintptr ) uintptr {
x := (*stringStruct )(a )
return memhashFallback (x .str , h , uintptr (x .len ))
}
func f32hash (p unsafe .Pointer , h uintptr ) uintptr {
f := *(*float32 )(p )
switch {
case f == 0 :
return c1 * (c0 ^ h )
case f != f :
return c1 * (c0 ^ h ^ uintptr (fastrand ()))
default :
return memhash (p , h , 4 )
}
}
func f64hash (p unsafe .Pointer , h uintptr ) uintptr {
f := *(*float64 )(p )
switch {
case f == 0 :
return c1 * (c0 ^ h )
case f != f :
return c1 * (c0 ^ h ^ uintptr (fastrand ()))
default :
return memhash (p , h , 8 )
}
}
func c64hash (p unsafe .Pointer , h uintptr ) uintptr {
x := (*[2 ]float32 )(p )
return f32hash (unsafe .Pointer (&x [1 ]), f32hash (unsafe .Pointer (&x [0 ]), h ))
}
func c128hash (p unsafe .Pointer , h uintptr ) uintptr {
x := (*[2 ]float64 )(p )
return f64hash (unsafe .Pointer (&x [1 ]), f64hash (unsafe .Pointer (&x [0 ]), h ))
}
func interhash (p unsafe .Pointer , h uintptr ) uintptr {
a := (*iface )(p )
tab := a .tab
if tab == nil {
return h
}
t := tab ._type
if t .Equal == nil {
panic (errorString ("hash of unhashable type " + toRType (t ).string ()))
}
if isDirectIface (t ) {
return c1 * typehash (t , unsafe .Pointer (&a .data ), h ^c0 )
} else {
return c1 * typehash (t , a .data , h ^c0 )
}
}
func nilinterhash (p unsafe .Pointer , h uintptr ) uintptr {
a := (*eface )(p )
t := a ._type
if t == nil {
return h
}
if t .Equal == nil {
panic (errorString ("hash of unhashable type " + toRType (t ).string ()))
}
if isDirectIface (t ) {
return c1 * typehash (t , unsafe .Pointer (&a .data ), h ^c0 )
} else {
return c1 * typehash (t , a .data , h ^c0 )
}
}
func typehash (t *_type , p unsafe .Pointer , h uintptr ) uintptr {
if t .TFlag &abi .TFlagRegularMemory != 0 {
switch t .Size_ {
case 4 :
return memhash32 (p , h )
case 8 :
return memhash64 (p , h )
default :
return memhash (p , h , t .Size_ )
}
}
switch t .Kind_ & kindMask {
case kindFloat32 :
return f32hash (p , h )
case kindFloat64 :
return f64hash (p , h )
case kindComplex64 :
return c64hash (p , h )
case kindComplex128 :
return c128hash (p , h )
case kindString :
return strhash (p , h )
case kindInterface :
i := (*interfacetype )(unsafe .Pointer (t ))
if len (i .Methods ) == 0 {
return nilinterhash (p , h )
}
return interhash (p , h )
case kindArray :
a := (*arraytype )(unsafe .Pointer (t ))
for i := uintptr (0 ); i < a .Len ; i ++ {
h = typehash (a .Elem , add (p , i *a .Elem .Size_ ), h )
}
return h
case kindStruct :
s := (*structtype )(unsafe .Pointer (t ))
for _ , f := range s .Fields {
if f .Name .IsBlank () {
continue
}
h = typehash (f .Typ , add (p , f .Offset ), h )
}
return h
default :
panic (errorString ("hash of unhashable type " + toRType (t ).string ()))
}
}
func reflect_typehash (t *_type , p unsafe .Pointer , h uintptr ) uintptr {
return typehash (t , p , h )
}
func memequal0 (p , q unsafe .Pointer ) bool {
return true
}
func memequal8 (p , q unsafe .Pointer ) bool {
return *(*int8 )(p ) == *(*int8 )(q )
}
func memequal16 (p , q unsafe .Pointer ) bool {
return *(*int16 )(p ) == *(*int16 )(q )
}
func memequal32 (p , q unsafe .Pointer ) bool {
return *(*int32 )(p ) == *(*int32 )(q )
}
func memequal64 (p , q unsafe .Pointer ) bool {
return *(*int64 )(p ) == *(*int64 )(q )
}
func memequal128 (p , q unsafe .Pointer ) bool {
return *(*[2 ]int64 )(p ) == *(*[2 ]int64 )(q )
}
func f32equal (p , q unsafe .Pointer ) bool {
return *(*float32 )(p ) == *(*float32 )(q )
}
func f64equal (p , q unsafe .Pointer ) bool {
return *(*float64 )(p ) == *(*float64 )(q )
}
func c64equal (p , q unsafe .Pointer ) bool {
return *(*complex64 )(p ) == *(*complex64 )(q )
}
func c128equal (p , q unsafe .Pointer ) bool {
return *(*complex128 )(p ) == *(*complex128 )(q )
}
func strequal (p , q unsafe .Pointer ) bool {
return *(*string )(p ) == *(*string )(q )
}
func interequal (p , q unsafe .Pointer ) bool {
x := *(*iface )(p )
y := *(*iface )(q )
return x .tab == y .tab && ifaceeq (x .tab , x .data , y .data )
}
func nilinterequal (p , q unsafe .Pointer ) bool {
x := *(*eface )(p )
y := *(*eface )(q )
return x ._type == y ._type && efaceeq (x ._type , x .data , y .data )
}
func efaceeq (t *_type , x , y unsafe .Pointer ) bool {
if t == nil {
return true
}
eq := t .Equal
if eq == nil {
panic (errorString ("comparing uncomparable type " + toRType (t ).string ()))
}
if isDirectIface (t ) {
return x == y
}
return eq (x , y )
}
func ifaceeq (tab *itab , x , y unsafe .Pointer ) bool {
if tab == nil {
return true
}
t := tab ._type
eq := t .Equal
if eq == nil {
panic (errorString ("comparing uncomparable type " + toRType (t ).string ()))
}
if isDirectIface (t ) {
return x == y
}
return eq (x , y )
}
func stringHash (s string , seed uintptr ) uintptr {
return strhash (noescape (unsafe .Pointer (&s )), seed )
}
func bytesHash (b []byte , seed uintptr ) uintptr {
s := (*slice )(unsafe .Pointer (&b ))
return memhash (s .array , seed , uintptr (s .len ))
}
func int32Hash (i uint32 , seed uintptr ) uintptr {
return memhash32 (noescape (unsafe .Pointer (&i )), seed )
}
func int64Hash (i uint64 , seed uintptr ) uintptr {
return memhash64 (noescape (unsafe .Pointer (&i )), seed )
}
func efaceHash (i any , seed uintptr ) uintptr {
return nilinterhash (noescape (unsafe .Pointer (&i )), seed )
}
func ifaceHash (i interface {
F ()
}, seed uintptr ) uintptr {
return interhash (noescape (unsafe .Pointer (&i )), seed )
}
const hashRandomBytes = goarch .PtrSize / 4 * 64
var aeskeysched [hashRandomBytes ]byte
var hashkey [4 ]uintptr
func alginit () {
if (GOARCH == "386" || GOARCH == "amd64" ) &&
cpu .X86 .HasAES &&
cpu .X86 .HasSSSE3 &&
cpu .X86 .HasSSE41 {
initAlgAES ()
return
}
if GOARCH == "arm64" && cpu .ARM64 .HasAES {
initAlgAES ()
return
}
getRandomData ((*[len (hashkey ) * goarch .PtrSize ]byte )(unsafe .Pointer (&hashkey ))[:])
hashkey [0 ] |= 1
hashkey [1 ] |= 1
hashkey [2 ] |= 1
hashkey [3 ] |= 1
}
func initAlgAES () {
useAeshash = true
getRandomData (aeskeysched [:])
}
func readUnaligned32 (p unsafe .Pointer ) uint32 {
q := (*[4 ]byte )(p )
if goarch .BigEndian {
return uint32 (q [3 ]) | uint32 (q [2 ])<<8 | uint32 (q [1 ])<<16 | uint32 (q [0 ])<<24
}
return uint32 (q [0 ]) | uint32 (q [1 ])<<8 | uint32 (q [2 ])<<16 | uint32 (q [3 ])<<24
}
func readUnaligned64 (p unsafe .Pointer ) uint64 {
q := (*[8 ]byte )(p )
if goarch .BigEndian {
return uint64 (q [7 ]) | uint64 (q [6 ])<<8 | uint64 (q [5 ])<<16 | uint64 (q [4 ])<<24 |
uint64 (q [3 ])<<32 | uint64 (q [2 ])<<40 | uint64 (q [1 ])<<48 | uint64 (q [0 ])<<56
}
return uint64 (q [0 ]) | uint64 (q [1 ])<<8 | uint64 (q [2 ])<<16 | uint64 (q [3 ])<<24 | uint64 (q [4 ])<<32 | uint64 (q [5 ])<<40 | uint64 (q [6 ])<<48 | uint64 (q [7 ])<<56
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .