mirror of
https://github.com/tursom/GoCollections.git
synced 2024-12-29 01:50:19 +08:00
205 lines
4.0 KiB
Go
205 lines
4.0 KiB
Go
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()
|
|
}
|
|
}
|