package search import ( "codeberg.org/snonux/algorithms/ds" ) type Hash[K ds.Integer,V ds.Number] struct { buckets []*Elementary[K,V] capacity int size int } func NewHash[K ds.Integer,V ds.Number](capacity int) *Hash[K,V] { return &Hash[K,V]{ buckets: make([]*Elementary[K,V], capacity), capacity: capacity, } } func (h *Hash[K,V]) Empty() bool { return h.Size() == 0 } func (h *Hash[K,V]) Size() int { return h.size } func (h *Hash[K,V]) hash(key K) int { // Mix the key in a full-width int64 rather than in K. K is any ds.Integer, // so for a narrow type (e.g. int8) the "key<<10" term would shift past the // type width and vanish to 0, destroying the intended high-bit mixing (and // go vet rightly flags it). Widening to int64 first keeps the result // identical for 64-bit int keys while making the mix well-defined for every // integer width. i := int64(key) i = i + i*2 + i<<10 + i>>2 if i < 0 { i = -i } return int(i) % h.capacity } func (h *Hash[K,V]) Put(key K, val V) { i := h.hash(key) if h.buckets[i] == nil { elem := NewElementary[K,V]() elem.Put(key, val) h.buckets[i] = elem return } h.buckets[i].Put(key, val) } func (h *Hash[K,V]) Get(key K) (V, error) { i := h.hash(key) if h.buckets[i] == nil { return 0, NotFound } return h.buckets[i].Get(key) } func (h *Hash[K,V]) Del(key K) (V, error) { i := h.hash(key) if h.buckets[i] == nil { return 0, NotFound } return h.buckets[i].Del(key) }