github.com/elves/elvish@v0.15.0/pkg/eval/vals/hash.go (about)

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