github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/eval/vals/hash.go (about) 1 package vals 2 3 import ( 4 "math" 5 "math/big" 6 "reflect" 7 8 "github.com/markusbkk/elvish/pkg/persistent/hash" 9 ) 10 11 // Hasher wraps the Hash method. 12 type Hasher interface { 13 // Hash computes the hash code of the receiver. 14 Hash() uint32 15 } 16 17 // Hash returns the 32-bit hash of a value. It is implemented for the builtin 18 // types bool and string, the File, List, Map types, StructMap types, and types 19 // satisfying the Hasher interface. For other values, it returns 0 (which is OK 20 // in terms of correctness). 21 func Hash(v interface{}) uint32 { 22 switch v := v.(type) { 23 case bool: 24 if v { 25 return 1 26 } 27 return 0 28 case int: 29 return hash.UIntPtr(uintptr(v)) 30 case *big.Int: 31 h := hash.DJBCombine(hash.DJBInit, uint32(v.Sign())) 32 for _, word := range v.Bits() { 33 h = hash.DJBCombine(h, hash.UIntPtr(uintptr(word))) 34 } 35 return h 36 case *big.Rat: 37 return hash.DJB(Hash(v.Num()), Hash(v.Denom())) 38 case float64: 39 return hash.UInt64(math.Float64bits(v)) 40 case string: 41 return hash.String(v) 42 case Hasher: 43 return v.Hash() 44 case File: 45 return hash.UIntPtr(v.Fd()) 46 case List: 47 h := hash.DJBInit 48 for it := v.Iterator(); it.HasElem(); it.Next() { 49 h = hash.DJBCombine(h, Hash(it.Elem())) 50 } 51 return h 52 case Map: 53 h := hash.DJBInit 54 for it := v.Iterator(); it.HasElem(); it.Next() { 55 k, v := it.Elem() 56 h = hash.DJBCombine(h, Hash(k)) 57 h = hash.DJBCombine(h, Hash(v)) 58 } 59 return h 60 case StructMap: 61 h := hash.DJBInit 62 it := iterateStructMap(reflect.TypeOf(v)) 63 vValue := reflect.ValueOf(v) 64 for it.Next() { 65 _, field := it.Get(vValue) 66 h = hash.DJBCombine(h, Hash(field)) 67 } 68 return h 69 } 70 return 0 71 }