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  }