GoCollections/collections/Map.go
2022-11-25 18:19:33 +08:00

178 lines
3.8 KiB
Go

/*
* Copyright (c) 2022 tursom. All rights reserved.
* Use of this source code is governed by a GPL-3
* license that can be found in the LICENSE file.
*/
package collections
import (
"fmt"
"strings"
"github.com/tursom/GoCollections/exceptions"
"github.com/tursom/GoCollections/lang"
)
type (
MapLooper[K lang.Object, V any] interface {
Loop(func(K, V) exceptions.Exception) exceptions.Exception
}
Map[K lang.Object, V any] interface {
MapLooper[K, V]
Get(k K) (V, bool, exceptions.Exception)
}
MutableMap[K lang.Object, V any] interface {
Map[K, V]
Put(k K, v V) (bool, exceptions.Exception)
Remove(k K) (V, bool, exceptions.Exception)
}
MapNodeFinder[K lang.Object, V any] interface {
findNode(k K, createIfNotExist bool) (node, prev MapNode[K, V])
}
MapSlotFinder[K lang.Object, V any] interface {
FindSlot(k K) (root MapNode[K, V])
}
MapNode[K lang.Object, V any] interface {
GetKey() K
GetValue() V
SetValue(value V)
CreateNext(key K) MapNode[K, V]
GetNext() MapNode[K, V]
RemoveNext()
}
SimpleMapNode[K lang.Object, V any] struct {
lang.BaseObject
key K
value V
next *SimpleMapNode[K, V]
}
NodeMap[K lang.Object, V any] struct {
lang.BaseObject
MapNodeFinder MapNodeFinder[K, V]
}
MapNodeFinderBySlot[K lang.Object, V any] struct {
lang.BaseObject
slotFinder MapSlotFinder[K, V]
}
)
func NewMapNodeFinderBySlot[K lang.Object, V any](slotFinder MapSlotFinder[K, V]) MapNodeFinder[K, V] {
return &MapNodeFinderBySlot[K, V]{slotFinder: slotFinder}
}
func MapToString[K lang.Object, V any](m MapLooper[K, V]) lang.String {
builder := strings.Builder{}
builder.WriteString("{")
_ = m.Loop(func(k K, v V) exceptions.Exception {
if builder.Len() != 1 {
builder.WriteString(", ")
}
builder.WriteString(k.String())
builder.WriteString(": ")
if ov, ok := lang.TryCast[lang.Object](v); ok {
builder.WriteString(ov.String())
} else {
builder.WriteString(fmt.Sprint(v))
}
return nil
})
builder.WriteString("}")
return lang.NewString(builder.String())
}
func (g *NodeMap[K, V]) findNode(k K, createIfNotExist bool) (node, prev MapNode[K, V]) {
return g.MapNodeFinder.findNode(k, createIfNotExist)
}
func (g *NodeMap[K, V]) Put(k K, v V) (bool, exceptions.Exception) {
node, _ := g.findNode(k, true)
node.SetValue(v)
return true, nil
}
func (g *NodeMap[K, V]) Get(k K) (V, bool, exceptions.Exception) {
node, _ := g.findNode(k, false)
if node == nil {
return g.nil()
} else {
return node.GetValue(), true, nil
}
}
func (g *NodeMap[K, V]) Remove(k K) (V, bool, exceptions.Exception) {
node, prev := g.findNode(k, false)
if node == nil {
return g.nil()
} else {
if prev != nil {
prev.RemoveNext()
}
return node.GetValue(), true, nil
}
}
func (g *NodeMap[K, V]) nil() (V, bool, exceptions.Exception) {
return lang.Nil[V](), false, nil
}
func (m *MapNodeFinderBySlot[K, V]) findNode(k K, createIfNotExist bool) (node, prev MapNode[K, V]) {
prev = m.slotFinder.FindSlot(k)
if prev != nil {
node = prev.GetNext()
for node != nil {
if node.GetKey().Equals(k) {
return
}
prev = node
node = node.GetNext()
}
}
if createIfNotExist {
node = prev.CreateNext(k)
}
return
}
func (s *SimpleMapNode[K, V]) String() string {
return "SimpleMapNode{key: " + s.key.String() + ", value: " + fmt.Sprint(s.value) + "}"
}
func (s *SimpleMapNode[K, V]) GetKey() K {
return s.key
}
func (s *SimpleMapNode[K, V]) GetValue() V {
return s.value
}
func (s *SimpleMapNode[K, V]) SetValue(value V) {
s.value = value
}
func (s *SimpleMapNode[K, V]) CreateNext(key K) MapNode[K, V] {
s.next = &SimpleMapNode[K, V]{key: key, next: s.next}
return s.next
}
func (s *SimpleMapNode[K, V]) GetNext() MapNode[K, V] {
if s.next == nil {
return nil
}
return s.next
}
func (s *SimpleMapNode[K, V]) RemoveNext() {
if s.next != nil {
s.next = s.next.next
}
}