diff options
Diffstat (limited to 'vendor/codeberg.org/gruf/go-structr/hash.go')
-rw-r--r-- | vendor/codeberg.org/gruf/go-structr/hash.go | 74 |
1 files changed, 54 insertions, 20 deletions
diff --git a/vendor/codeberg.org/gruf/go-structr/hash.go b/vendor/codeberg.org/gruf/go-structr/hash.go index 84f0e62fc..ffdc5f5f1 100644 --- a/vendor/codeberg.org/gruf/go-structr/hash.go +++ b/vendor/codeberg.org/gruf/go-structr/hash.go @@ -2,11 +2,50 @@ package structr import ( "reflect" + "sync" "unsafe" "github.com/zeebo/xxh3" ) +var hash_pool sync.Pool + +func get_hasher() *xxh3.Hasher { + v := hash_pool.Get() + if v == nil { + v = new(xxh3.Hasher) + } + return v.(*xxh3.Hasher) +} + +func hash_sum(fields []structfield, h *xxh3.Hasher, key []any) (Hash, bool) { + if len(key) != len(fields) { + panicf("incorrect number key parts: want=%d received=%d", + len(key), + len(fields), + ) + } + var zero bool + h.Reset() + for i, part := range key { + zero = fields[i].hasher(h, part) || zero + } + // See: https://github.com/Cyan4973/xxHash/issues/453#issuecomment-696838445 + // + // In order to extract 32-bit from a good 64-bit hash result, + // there are many possible choices, which are all valid. + // I would typically grab the lower 32-bit and call it a day. + // + // Grabbing any other 32-bit (the upper part for example) is fine too. + // + // xoring higher and lower bits makes more sense whenever the produced hash offers dubious quality. + // FNV, for example, has poor mixing in its lower bits, so it's better to mix with the higher bits. + // + // XXH3 already performs significant output mixing before returning the data, + // so it's not beneficial to add another xorfold stage. + return uint64ToHash(h.Sum64()), zero +} + func hasher(t reflect.Type) func(*xxh3.Hasher, any) bool { switch t.Kind() { case reflect.Int, @@ -137,13 +176,13 @@ func hasher(t reflect.Type) func(*xxh3.Hasher, any) bool { } func hash8bit(h *xxh3.Hasher, a any) bool { - u := *(*uint8)(iface_value(a)) + u := *(*uint8)(data_ptr(a)) _, _ = h.Write([]byte{u}) return u == 0 } func hash8bitptr(h *xxh3.Hasher, a any) bool { - u := (*uint8)(iface_value(a)) + u := (*uint8)(data_ptr(a)) if u == nil { _, _ = h.Write([]byte{ 0, @@ -159,13 +198,13 @@ func hash8bitptr(h *xxh3.Hasher, a any) bool { } func hash8bitslice(h *xxh3.Hasher, a any) bool { - b := *(*[]byte)(iface_value(a)) + b := *(*[]byte)(data_ptr(a)) _, _ = h.Write(b) return b == nil } func hash16bit(h *xxh3.Hasher, a any) bool { - u := *(*uint16)(iface_value(a)) + u := *(*uint16)(data_ptr(a)) _, _ = h.Write([]byte{ byte(u), byte(u >> 8), @@ -174,7 +213,7 @@ func hash16bit(h *xxh3.Hasher, a any) bool { } func hash16bitptr(h *xxh3.Hasher, a any) bool { - u := (*uint16)(iface_value(a)) + u := (*uint16)(data_ptr(a)) if u == nil { _, _ = h.Write([]byte{ 0, @@ -191,7 +230,7 @@ func hash16bitptr(h *xxh3.Hasher, a any) bool { } func hash16bitslice(h *xxh3.Hasher, a any) bool { - u := *(*[]uint16)(iface_value(a)) + u := *(*[]uint16)(data_ptr(a)) for i := range u { _, _ = h.Write([]byte{ byte(u[i]), @@ -202,7 +241,7 @@ func hash16bitslice(h *xxh3.Hasher, a any) bool { } func hash32bit(h *xxh3.Hasher, a any) bool { - u := *(*uint32)(iface_value(a)) + u := *(*uint32)(data_ptr(a)) _, _ = h.Write([]byte{ byte(u), byte(u >> 8), @@ -213,7 +252,7 @@ func hash32bit(h *xxh3.Hasher, a any) bool { } func hash32bitptr(h *xxh3.Hasher, a any) bool { - u := (*uint32)(iface_value(a)) + u := (*uint32)(data_ptr(a)) if u == nil { _, _ = h.Write([]byte{ 0, @@ -232,7 +271,7 @@ func hash32bitptr(h *xxh3.Hasher, a any) bool { } func hash32bitslice(h *xxh3.Hasher, a any) bool { - u := *(*[]uint32)(iface_value(a)) + u := *(*[]uint32)(data_ptr(a)) for i := range u { _, _ = h.Write([]byte{ byte(u[i]), @@ -245,7 +284,7 @@ func hash32bitslice(h *xxh3.Hasher, a any) bool { } func hash64bit(h *xxh3.Hasher, a any) bool { - u := *(*uint64)(iface_value(a)) + u := *(*uint64)(data_ptr(a)) _, _ = h.Write([]byte{ byte(u), byte(u >> 8), @@ -260,7 +299,7 @@ func hash64bit(h *xxh3.Hasher, a any) bool { } func hash64bitptr(h *xxh3.Hasher, a any) bool { - u := (*uint64)(iface_value(a)) + u := (*uint64)(data_ptr(a)) if u == nil { _, _ = h.Write([]byte{ 0, @@ -283,7 +322,7 @@ func hash64bitptr(h *xxh3.Hasher, a any) bool { } func hash64bitslice(h *xxh3.Hasher, a any) bool { - u := *(*[]uint64)(iface_value(a)) + u := *(*[]uint64)(data_ptr(a)) for i := range u { _, _ = h.Write([]byte{ byte(u[i]), @@ -300,13 +339,13 @@ func hash64bitslice(h *xxh3.Hasher, a any) bool { } func hashstring(h *xxh3.Hasher, a any) bool { - s := *(*string)(iface_value(a)) + s := *(*string)(data_ptr(a)) _, _ = h.WriteString(s) return s == "" } func hashstringptr(h *xxh3.Hasher, a any) bool { - s := (*string)(iface_value(a)) + s := (*string)(data_ptr(a)) if s == nil { _, _ = h.Write([]byte{ 0, @@ -322,7 +361,7 @@ func hashstringptr(h *xxh3.Hasher, a any) bool { } func hashstringslice(h *xxh3.Hasher, a any) bool { - s := *(*[]string)(iface_value(a)) + s := *(*[]string)(data_ptr(a)) for i := range s { _, _ = h.WriteString(s[i]) } @@ -363,8 +402,3 @@ func hashjsonmarshaler(h *xxh3.Hasher, a any) bool { _, _ = h.Write(b) return b == nil } - -func iface_value(a any) unsafe.Pointer { - type eface struct{ _, v unsafe.Pointer } - return (*eface)(unsafe.Pointer(&a)).v -} |