mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-05 03:17:50 +08:00
72 lines
1.6 KiB
Go
72 lines
1.6 KiB
Go
package vals
|
|
|
|
import (
|
|
"math"
|
|
"math/big"
|
|
"reflect"
|
|
|
|
"src.elv.sh/pkg/persistent/hash"
|
|
)
|
|
|
|
// Hasher wraps the Hash method.
|
|
type Hasher interface {
|
|
// Hash computes the hash code of the receiver.
|
|
Hash() uint32
|
|
}
|
|
|
|
// Hash returns the 32-bit hash of a value. It is implemented for the builtin
|
|
// types bool and string, the File, List, Map types, StructMap types, and types
|
|
// satisfying the Hasher interface. For other values, it returns 0 (which is OK
|
|
// in terms of correctness).
|
|
func Hash(v interface{}) uint32 {
|
|
switch v := v.(type) {
|
|
case bool:
|
|
if v {
|
|
return 1
|
|
}
|
|
return 0
|
|
case int:
|
|
return hash.UIntPtr(uintptr(v))
|
|
case *big.Int:
|
|
h := hash.DJBCombine(hash.DJBInit, uint32(v.Sign()))
|
|
for _, word := range v.Bits() {
|
|
h = hash.DJBCombine(h, hash.UIntPtr(uintptr(word)))
|
|
}
|
|
return h
|
|
case *big.Rat:
|
|
return hash.DJB(Hash(v.Num()), Hash(v.Denom()))
|
|
case float64:
|
|
return hash.UInt64(math.Float64bits(v))
|
|
case string:
|
|
return hash.String(v)
|
|
case Hasher:
|
|
return v.Hash()
|
|
case File:
|
|
return hash.UIntPtr(v.Fd())
|
|
case List:
|
|
h := hash.DJBInit
|
|
for it := v.Iterator(); it.HasElem(); it.Next() {
|
|
h = hash.DJBCombine(h, Hash(it.Elem()))
|
|
}
|
|
return h
|
|
case Map:
|
|
h := hash.DJBInit
|
|
for it := v.Iterator(); it.HasElem(); it.Next() {
|
|
k, v := it.Elem()
|
|
h = hash.DJBCombine(h, Hash(k))
|
|
h = hash.DJBCombine(h, Hash(v))
|
|
}
|
|
return h
|
|
case StructMap:
|
|
h := hash.DJBInit
|
|
it := iterateStructMap(reflect.TypeOf(v))
|
|
vValue := reflect.ValueOf(v)
|
|
for it.Next() {
|
|
_, field := it.Get(vValue)
|
|
h = hash.DJBCombine(h, Hash(field))
|
|
}
|
|
return h
|
|
}
|
|
return 0
|
|
}
|