diff options
Diffstat (limited to 'vendor/codeberg.org/gruf/go-structr/hash.go')
-rw-r--r-- | vendor/codeberg.org/gruf/go-structr/hash.go | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/vendor/codeberg.org/gruf/go-structr/hash.go b/vendor/codeberg.org/gruf/go-structr/hash.go new file mode 100644 index 000000000..84f0e62fc --- /dev/null +++ b/vendor/codeberg.org/gruf/go-structr/hash.go @@ -0,0 +1,370 @@ +package structr + +import ( + "reflect" + "unsafe" + + "github.com/zeebo/xxh3" +) + +func hasher(t reflect.Type) func(*xxh3.Hasher, any) bool { + switch t.Kind() { + case reflect.Int, + reflect.Uint, + reflect.Uintptr: + switch unsafe.Sizeof(int(0)) { + case 4: + return hash32bit + case 8: + return hash64bit + default: + panic("unexpected platform int size") + } + + case reflect.Int8, + reflect.Uint8: + return hash8bit + + case reflect.Int16, + reflect.Uint16: + return hash16bit + + case reflect.Int32, + reflect.Uint32, + reflect.Float32: + return hash32bit + + case reflect.Int64, + reflect.Uint64, + reflect.Float64, + reflect.Complex64: + return hash64bit + + case reflect.String: + return hashstring + + case reflect.Pointer: + switch t.Elem().Kind() { + case reflect.Int, + reflect.Uint, + reflect.Uintptr: + switch unsafe.Sizeof(int(0)) { + case 4: + return hash32bitptr + case 8: + return hash64bitptr + default: + panic("unexpected platform int size") + } + + case reflect.Int8, + reflect.Uint8: + return hash8bitptr + + case reflect.Int16, + reflect.Uint16: + return hash16bitptr + + case reflect.Int32, + reflect.Uint32, + reflect.Float32: + return hash32bitptr + + case reflect.Int64, + reflect.Uint64, + reflect.Float64, + reflect.Complex64: + return hash64bitptr + + case reflect.String: + return hashstringptr + } + + case reflect.Slice: + switch t.Elem().Kind() { + case reflect.Int, + reflect.Uint, + reflect.Uintptr: + switch unsafe.Sizeof(int(0)) { + case 4: + return hash32bitslice + case 8: + return hash64bitslice + default: + panic("unexpected platform int size") + } + + case reflect.Int8, + reflect.Uint8: + return hash8bitslice + + case reflect.Int16, + reflect.Uint16: + return hash16bitslice + + case reflect.Int32, + reflect.Uint32, + reflect.Float32: + return hash32bitslice + + case reflect.Int64, + reflect.Uint64, + reflect.Float64, + reflect.Complex64: + return hash64bitslice + + case reflect.String: + return hashstringslice + } + } + switch { + case t.Implements(reflect.TypeOf((*interface{ MarshalBinary() ([]byte, error) })(nil)).Elem()): + return hashbinarymarshaler + + case t.Implements(reflect.TypeOf((*interface{ Bytes() []byte })(nil)).Elem()): + return hashbytesmethod + + case t.Implements(reflect.TypeOf((*interface{ String() string })(nil)).Elem()): + return hashstringmethod + + case t.Implements(reflect.TypeOf((*interface{ MarshalText() ([]byte, error) })(nil)).Elem()): + return hashtextmarshaler + + case t.Implements(reflect.TypeOf((*interface{ MarshalJSON() ([]byte, error) })(nil)).Elem()): + return hashjsonmarshaler + } + panic("unhashable type") +} + +func hash8bit(h *xxh3.Hasher, a any) bool { + u := *(*uint8)(iface_value(a)) + _, _ = h.Write([]byte{u}) + return u == 0 +} + +func hash8bitptr(h *xxh3.Hasher, a any) bool { + u := (*uint8)(iface_value(a)) + if u == nil { + _, _ = h.Write([]byte{ + 0, + }) + return true + } else { + _, _ = h.Write([]byte{ + 1, + byte(*u), + }) + return false + } +} + +func hash8bitslice(h *xxh3.Hasher, a any) bool { + b := *(*[]byte)(iface_value(a)) + _, _ = h.Write(b) + return b == nil +} + +func hash16bit(h *xxh3.Hasher, a any) bool { + u := *(*uint16)(iface_value(a)) + _, _ = h.Write([]byte{ + byte(u), + byte(u >> 8), + }) + return u == 0 +} + +func hash16bitptr(h *xxh3.Hasher, a any) bool { + u := (*uint16)(iface_value(a)) + if u == nil { + _, _ = h.Write([]byte{ + 0, + }) + return true + } else { + _, _ = h.Write([]byte{ + 1, + byte(*u), + byte(*u >> 8), + }) + return false + } +} + +func hash16bitslice(h *xxh3.Hasher, a any) bool { + u := *(*[]uint16)(iface_value(a)) + for i := range u { + _, _ = h.Write([]byte{ + byte(u[i]), + byte(u[i] >> 8), + }) + } + return u == nil +} + +func hash32bit(h *xxh3.Hasher, a any) bool { + u := *(*uint32)(iface_value(a)) + _, _ = h.Write([]byte{ + byte(u), + byte(u >> 8), + byte(u >> 16), + byte(u >> 24), + }) + return u == 0 +} + +func hash32bitptr(h *xxh3.Hasher, a any) bool { + u := (*uint32)(iface_value(a)) + if u == nil { + _, _ = h.Write([]byte{ + 0, + }) + return true + } else { + _, _ = h.Write([]byte{ + 1, + byte(*u), + byte(*u >> 8), + byte(*u >> 16), + byte(*u >> 24), + }) + return false + } +} + +func hash32bitslice(h *xxh3.Hasher, a any) bool { + u := *(*[]uint32)(iface_value(a)) + for i := range u { + _, _ = h.Write([]byte{ + byte(u[i]), + byte(u[i] >> 8), + byte(u[i] >> 16), + byte(u[i] >> 24), + }) + } + return u == nil +} + +func hash64bit(h *xxh3.Hasher, a any) bool { + u := *(*uint64)(iface_value(a)) + _, _ = h.Write([]byte{ + byte(u), + byte(u >> 8), + byte(u >> 16), + byte(u >> 24), + byte(u >> 32), + byte(u >> 40), + byte(u >> 48), + byte(u >> 56), + }) + return u == 0 +} + +func hash64bitptr(h *xxh3.Hasher, a any) bool { + u := (*uint64)(iface_value(a)) + if u == nil { + _, _ = h.Write([]byte{ + 0, + }) + return true + } else { + _, _ = h.Write([]byte{ + 1, + byte(*u), + byte(*u >> 8), + byte(*u >> 16), + byte(*u >> 24), + byte(*u >> 32), + byte(*u >> 40), + byte(*u >> 48), + byte(*u >> 56), + }) + return false + } +} + +func hash64bitslice(h *xxh3.Hasher, a any) bool { + u := *(*[]uint64)(iface_value(a)) + for i := range u { + _, _ = h.Write([]byte{ + byte(u[i]), + byte(u[i] >> 8), + byte(u[i] >> 16), + byte(u[i] >> 24), + byte(u[i] >> 32), + byte(u[i] >> 40), + byte(u[i] >> 48), + byte(u[i] >> 56), + }) + } + return u == nil +} + +func hashstring(h *xxh3.Hasher, a any) bool { + s := *(*string)(iface_value(a)) + _, _ = h.WriteString(s) + return s == "" +} + +func hashstringptr(h *xxh3.Hasher, a any) bool { + s := (*string)(iface_value(a)) + if s == nil { + _, _ = h.Write([]byte{ + 0, + }) + return true + } else { + _, _ = h.Write([]byte{ + 1, + }) + _, _ = h.WriteString(*s) + return false + } +} + +func hashstringslice(h *xxh3.Hasher, a any) bool { + s := *(*[]string)(iface_value(a)) + for i := range s { + _, _ = h.WriteString(s[i]) + } + return s == nil +} + +func hashbinarymarshaler(h *xxh3.Hasher, a any) bool { + i := a.(interface{ MarshalBinary() ([]byte, error) }) + b, _ := i.MarshalBinary() + _, _ = h.Write(b) + return b == nil +} + +func hashbytesmethod(h *xxh3.Hasher, a any) bool { + i := a.(interface{ Bytes() []byte }) + b := i.Bytes() + _, _ = h.Write(b) + return b == nil +} + +func hashstringmethod(h *xxh3.Hasher, a any) bool { + i := a.(interface{ String() string }) + s := i.String() + _, _ = h.WriteString(s) + return s == "" +} + +func hashtextmarshaler(h *xxh3.Hasher, a any) bool { + i := a.(interface{ MarshalText() ([]byte, error) }) + b, _ := i.MarshalText() + _, _ = h.Write(b) + return b == nil +} + +func hashjsonmarshaler(h *xxh3.Hasher, a any) bool { + i := a.(interface{ MarshalJSON() ([]byte, error) }) + b, _ := i.MarshalJSON() + _, _ = 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 +} |