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  }