github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/internal/hash/hash.go (about) 1 package hash 2 3 import ( 4 "hash" 5 "reflect" 6 "sync" 7 "unsafe" 8 9 "github.com/dchest/siphash" 10 11 "github.com/hirochachacha/plua/internal/limits" 12 "github.com/hirochachacha/plua/internal/rand" 13 14 "github.com/hirochachacha/plua/object" 15 ) 16 17 type Hash struct { 18 h hash.Hash64 19 m sync.Mutex 20 } 21 22 func New() *Hash { 23 return &Hash{h: siphash.New(rand.Bytes(16))} 24 } 25 26 func (h *Hash) Sum(key object.Value) (sum uint64) { 27 h.m.Lock() 28 defer h.m.Unlock() 29 30 h.h.Reset() 31 32 switch key := key.(type) { 33 case nil: 34 return 0 35 case object.Integer: 36 h.h.Write((*(*[8]byte)(unsafe.Pointer(&key)))[:]) 37 case object.Number: 38 h.h.Write((*(*[8]byte)(unsafe.Pointer(&key)))[:]) 39 case object.String: 40 sheader := (*reflect.StringHeader)(unsafe.Pointer(&key)) 41 42 bheader := &reflect.SliceHeader{ 43 Data: sheader.Data, 44 Len: sheader.Len, 45 Cap: sheader.Len, 46 } 47 48 h.h.Write(*(*[]byte)(unsafe.Pointer(bheader))) 49 case object.Boolean: 50 h.h.Write((*(*[1]byte)(unsafe.Pointer(&key)))[:]) 51 case object.LightUserdata: 52 ikey := uintptr(key.Pointer) 53 h.h.Write((*(*[limits.PtrSize]byte)(unsafe.Pointer(&ikey)))[:]) 54 case object.GoFunction: 55 ikey := uintptr(reflect.ValueOf(key).Pointer()) 56 h.h.Write((*(*[limits.PtrSize]byte)(unsafe.Pointer(&ikey)))[:]) 57 default: 58 ikey := uintptr(reflect.ValueOf(key).Pointer()) 59 h.h.Write((*(*[limits.PtrSize]byte)(unsafe.Pointer(&ikey)))[:]) 60 } 61 62 return h.h.Sum64() + 1 63 }