package collections import ( "fmt" "github.com/tursom/GoCollections/exceptions" "github.com/tursom/GoCollections/lang" ) type ( //HashMap HashMap[K lang.Object, V any] struct { NodeMap[K, V] slot []*hashMapNode[K, V] loadFactor float32 size int } abstractHashMapNode[K lang.Object, V any] struct { m *HashMap[K, V] hash int32 } hashMapNode[K lang.Object, V any] struct { lang.BaseObject abstractHashMapNode[K, V] key K value V next *hashMapNode[K, V] } emptyHashMapSlot[K lang.Object, V any] struct { lang.BaseObject abstractHashMapNode[K, V] } ) func NewHashMap[K lang.Object, V any]() *HashMap[K, V] { return NewHashMapInitCap[K, V](16, 0.75) } func NewHashMapInitCap[K lang.Object, V any](initialCapacity int, loadFactor float32) *HashMap[K, V] { m := &HashMap[K, V]{ slot: make([]*hashMapNode[K, V], initialCapacity), loadFactor: loadFactor, } m.MapNodeFinder = NewMapNodeFinderBySlot[K, V](m) return m } func (m *HashMap[K, V]) String() string { return MapToString[K, V](m).String() } func (m *HashMap[K, V]) findSlot(k K) MapNode[K, V] { hashCode := lang.HashCode(k) hashCode ^= hashCode >> 16 index := int(hashCode) % len(m.slot) root := m.slot[index] if root == nil { return &emptyHashMapSlot[K, V]{abstractHashMapNode: abstractHashMapNode[K, V]{m: m, hash: hashCode}} } return root } func (m *HashMap[K, V]) Loop(f func(K, V) exceptions.Exception) (err exceptions.Exception) { for _, node := range m.slot { for node != nil { err = f(node.GetKey(), node.GetValue()) if err != nil { return } node = node.next } } return } func (m *HashMap[K, V]) resize() { slot := m.slot resize := len(slot) load := int(float32(m.size) / m.loadFactor) for load < resize { resize >>= 1 } for load > resize { resize <<= 1 } if resize == len(slot) { return } m.slot = make([]*hashMapNode[K, V], resize) for _, node := range slot { for node != nil { next := node.next index := node.index() node.next = m.slot[index] m.slot[index] = node node = next } } } func (m *HashMap[K, V]) resizeFromRemove() { if len(m.slot) > int(float32(m.size)/m.loadFactor) { m.resize() } } func (m *HashMap[K, V]) resizeFromAdd() { if len(m.slot) < int(float32(m.size)/m.loadFactor) { m.resize() } } func (n *abstractHashMapNode[K, V]) index() int { return int(n.hash) % len(n.m.slot) } func (e *emptyHashMapSlot[K, V]) GetKey() K { return lang.Nil[K]() } func (e *emptyHashMapSlot[K, V]) GetValue() V { return lang.Nil[V]() } func (e *emptyHashMapSlot[K, V]) SetValue(_ V) { } func (e *emptyHashMapSlot[K, V]) CreateNext(key K) MapNode[K, V] { index := e.index() node := &hashMapNode[K, V]{ key: key, abstractHashMapNode: abstractHashMapNode[K, V]{m: e.m, hash: lang.HashCode(key)}, next: e.m.slot[index], } e.m.slot[index] = node e.m.size++ e.m.resizeFromAdd() return node } func (e *emptyHashMapSlot[K, V]) GetNext() MapNode[K, V] { node := e.m.slot[e.index()] // required if node == nil { return nil } return node } func (e *emptyHashMapSlot[K, V]) RemoveNext() { node := e.m.slot[e.index()] if node != nil { e.m.slot[e.index()] = node.next e.m.size-- e.m.resizeFromRemove() } } func (s *hashMapNode[K, V]) String() string { return "hashMapNode{key: " + s.key.String() + ", value: " + fmt.Sprint(s.value) + "}" } func (s *hashMapNode[K, V]) GetKey() K { return s.key } func (s *hashMapNode[K, V]) GetValue() V { return s.value } func (s *hashMapNode[K, V]) SetValue(value V) { s.value = value } func (s *hashMapNode[K, V]) CreateNext(key K) MapNode[K, V] { s.next = &hashMapNode[K, V]{ key: key, next: s.next, abstractHashMapNode: abstractHashMapNode[K, V]{ m: s.m, hash: lang.HashCode(key), }, } s.m.size++ s.m.resizeFromAdd() return s.next } func (s *hashMapNode[K, V]) GetNext() MapNode[K, V] { if s.next == nil { return nil } return s.next } func (s *hashMapNode[K, V]) RemoveNext() { if s.next != nil { s.next = s.next.next s.m.size-- s.m.resizeFromRemove() } }