/* * 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 } }