github.com/primecitizens/pcz/std@v0.2.1/core/hash/hash.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 4 package hash 5 6 import ( 7 "unsafe" 8 9 stdstring "github.com/primecitizens/pcz/std/builtin/string" 10 stdtype "github.com/primecitizens/pcz/std/builtin/type" 11 "github.com/primecitizens/pcz/std/core/abi" 12 "github.com/primecitizens/pcz/std/core/arch" 13 "github.com/primecitizens/pcz/std/core/assert" 14 "github.com/primecitizens/pcz/std/core/thread" 15 ) 16 17 var ( 18 // used in hash{32,64}.go to seed the hash function 19 hashkey [4]uintptr 20 ) 21 22 const ( 23 c0 = uintptr((8-arch.PtrSize)/4*2860486313 + (arch.PtrSize-4)/4*33054211828000289) 24 c1 = uintptr((8-arch.PtrSize)/4*3267000013 + (arch.PtrSize-4)/4*23344194077549503) 25 ) 26 27 func StringHash(p unsafe.Pointer, h uintptr) uintptr { 28 str := (*stdstring.Header)(p) 29 return MemHash(str.Str, h, uintptr(str.Len)) 30 } 31 32 func Float32Hash(p unsafe.Pointer, h uintptr) uintptr { 33 f := *(*float32)(p) 34 switch { 35 case f == 0: 36 return c1 * (c0 ^ h) // +0, -0 37 case f != f: 38 return c1 * (c0 ^ h ^ uintptr(thread.G().G().Rand32())) // any kind of NaN 39 default: 40 return MemHash(p, h, 4) 41 } 42 } 43 44 func Float64Hash(p unsafe.Pointer, h uintptr) uintptr { 45 f := *(*float64)(p) 46 switch { 47 case f == 0: 48 return c1 * (c0 ^ h) // +0, -0 49 case f != f: 50 return c1 * (c0 ^ h ^ uintptr(thread.G().G().Rand32())) // any kind of NaN 51 default: 52 return MemHash(p, h, 8) 53 } 54 } 55 56 func Complex64Hash(p unsafe.Pointer, h uintptr) uintptr { 57 x := (*[2]float32)(p) 58 return Float32Hash(unsafe.Pointer(&x[1]), Float32Hash(unsafe.Pointer(&x[0]), h)) 59 } 60 61 func Complex128Hash(p unsafe.Pointer, h uintptr) uintptr { 62 x := (*[2]float64)(p) 63 return Float64Hash(unsafe.Pointer(&x[1]), Float64Hash(unsafe.Pointer(&x[0]), h)) 64 } 65 66 func InterfaceHash(p unsafe.Pointer, h uintptr) uintptr { 67 a := (*stdtype.Iface)(p) 68 tab := a.Itab 69 if tab == nil { 70 return h 71 } 72 t := tab.Type 73 if t.Equal == nil { 74 // Check hashability here. We could do this check inside 75 // typehash, but we want to report the topmost type in 76 // the error text (e.g. in a struct with a field of slice type 77 // we want to report the struct, not the slice). 78 assert.Panic("hash", "of", "unhashable", "type ", t.String()) 79 return h 80 } 81 82 if t.IsDirectIface() { 83 return c1 * TypeHash(t, unsafe.Pointer(&a.Data), h^c0) 84 } else { 85 return c1 * TypeHash(t, a.Data, h^c0) 86 } 87 } 88 89 func NilInterfaceHash(p unsafe.Pointer, h uintptr) uintptr { 90 a := (*stdtype.Eface)(p) 91 t := a.Type 92 if t == nil { 93 return h 94 } 95 if t.Equal == nil { 96 // See comment in interhash above. 97 assert.Panic("hash", "of", "unhashable", "type ", t.String()) 98 return h 99 } 100 101 if t.IsDirectIface() { 102 return c1 * TypeHash(t, unsafe.Pointer(&a.Data), h^c0) 103 } else { 104 return c1 * TypeHash(t, a.Data, h^c0) 105 } 106 } 107 108 // TypeHash computes the hash of the object of type t at address p. 109 // h is the seed. 110 // This function is seldom used. Most maps use for hashing either 111 // fixed functions (e.g. f32hash) or compiler-generated functions 112 // (e.g. for a type like struct { x, y string }). This implementation 113 // is slower but more general and is used for hashing interface types 114 // (called from interhash or nilinterhash, above) or for hashing in 115 // maps generated by reflect.MapOf (reflect_typehash, below). 116 // Note: this function must match the compiler generated 117 // functions exactly. See issue 37716. 118 func TypeHash(t *abi.Type, p unsafe.Pointer, h uintptr) uintptr { 119 if t.TFlag&abi.TFlagRegularMemory != 0 { 120 // Handle ptr sizes specially, see issue 37086. 121 switch t.Size_ { 122 case 4: 123 return MemHash32(p, h) 124 case 8: 125 return MemHash64(p, h) 126 default: 127 return MemHash(p, h, t.Size_) 128 } 129 } 130 131 switch t.Kind() { 132 case abi.KindFloat32: 133 return Float32Hash(p, h) 134 case abi.KindFloat64: 135 return Float64Hash(p, h) 136 case abi.KindComplex64: 137 return Complex64Hash(p, h) 138 case abi.KindComplex128: 139 return Complex128Hash(p, h) 140 case abi.KindString: 141 return StringHash(p, h) 142 case abi.KindInterface: 143 if len(t.InterfaceType().Methods) == 0 { 144 return NilInterfaceHash(p, h) 145 } 146 return InterfaceHash(p, h) 147 case abi.KindArray: 148 for a, i := t.ArrayType(), uintptr(0); i < a.Len; i++ { 149 h = TypeHash(a.Elem, unsafe.Add(p, i*a.Elem.Size_), h) 150 } 151 return h 152 case abi.KindStruct: 153 s := t.StructType() 154 for _, f := range s.Fields { 155 if f.Name.IsBlank() { 156 continue 157 } 158 h = TypeHash(f.Typ, unsafe.Add(p, f.Offset), h) 159 } 160 return h 161 default: 162 // Should never happen, as typehash should only be called 163 // with comparable types. 164 assert.Panic("hash", "of", "unhashable", "type ", t.String()) 165 return h 166 } 167 }