mirror of
https://github.com/luxfi/container.git
synced 2026-09-24 00:24:34 +00:00
147 lines
3.0 KiB
Go
147 lines
3.0 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package linkedhashmap
|
|
|
|
import (
|
|
"container/list"
|
|
"sync"
|
|
)
|
|
|
|
var _ LinkedHashmap[int, struct{}] = (*linkedHashmap[int, struct{}])(nil)
|
|
|
|
// Hashmap provides an O(1) mapping from a comparable key to any value.
|
|
// Comparable is defined by https://golang.org/ref/spec#Comparison_operators.
|
|
type Hashmap[K, V any] interface {
|
|
Put(key K, val V)
|
|
Get(key K) (val V, exists bool)
|
|
Delete(key K) (deleted bool)
|
|
Len() int
|
|
}
|
|
|
|
// LinkedHashmap is a hashmap that keeps track of the oldest pairing an the
|
|
// newest pairing.
|
|
type LinkedHashmap[K, V any] interface {
|
|
Hashmap[K, V]
|
|
|
|
Oldest() (key K, val V, exists bool)
|
|
Newest() (key K, val V, exists bool)
|
|
NewIterator() Iter[K, V]
|
|
}
|
|
|
|
type keyValue[K, V any] struct {
|
|
key K
|
|
value V
|
|
}
|
|
|
|
type linkedHashmap[K comparable, V any] struct {
|
|
lock sync.RWMutex
|
|
entryMap map[K]*list.Element
|
|
entryList *list.List
|
|
}
|
|
|
|
func New[K comparable, V any]() LinkedHashmap[K, V] {
|
|
return &linkedHashmap[K, V]{
|
|
entryMap: make(map[K]*list.Element),
|
|
entryList: list.New(),
|
|
}
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) Put(key K, val V) {
|
|
lh.lock.Lock()
|
|
defer lh.lock.Unlock()
|
|
|
|
lh.put(key, val)
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) Get(key K) (V, bool) {
|
|
lh.lock.RLock()
|
|
defer lh.lock.RUnlock()
|
|
|
|
return lh.get(key)
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) Delete(key K) bool {
|
|
lh.lock.Lock()
|
|
defer lh.lock.Unlock()
|
|
|
|
return lh.delete(key)
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) Len() int {
|
|
lh.lock.RLock()
|
|
defer lh.lock.RUnlock()
|
|
|
|
return lh.len()
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) Oldest() (K, V, bool) {
|
|
lh.lock.RLock()
|
|
defer lh.lock.RUnlock()
|
|
|
|
return lh.oldest()
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) Newest() (K, V, bool) {
|
|
lh.lock.RLock()
|
|
defer lh.lock.RUnlock()
|
|
|
|
return lh.newest()
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) put(key K, value V) {
|
|
if e, ok := lh.entryMap[key]; ok {
|
|
lh.entryList.MoveToBack(e)
|
|
e.Value = keyValue[K, V]{
|
|
key: key,
|
|
value: value,
|
|
}
|
|
} else {
|
|
lh.entryMap[key] = lh.entryList.PushBack(keyValue[K, V]{
|
|
key: key,
|
|
value: value,
|
|
})
|
|
}
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) get(key K) (V, bool) {
|
|
if e, ok := lh.entryMap[key]; ok {
|
|
kv := e.Value.(keyValue[K, V])
|
|
return kv.value, true
|
|
}
|
|
return zero[V](), false
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) delete(key K) bool {
|
|
e, ok := lh.entryMap[key]
|
|
if ok {
|
|
lh.entryList.Remove(e)
|
|
delete(lh.entryMap, key)
|
|
}
|
|
return ok
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) len() int {
|
|
return len(lh.entryMap)
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) oldest() (K, V, bool) {
|
|
if val := lh.entryList.Front(); val != nil {
|
|
kv := val.Value.(keyValue[K, V])
|
|
return kv.key, kv.value, true
|
|
}
|
|
return zero[K](), zero[V](), false
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) newest() (K, V, bool) {
|
|
if val := lh.entryList.Back(); val != nil {
|
|
kv := val.Value.(keyValue[K, V])
|
|
return kv.key, kv.value, true
|
|
}
|
|
return zero[K](), zero[V](), false
|
|
}
|
|
|
|
func (lh *linkedHashmap[K, V]) NewIterator() Iter[K, V] {
|
|
return &iterator[K, V]{lh: lh}
|
|
}
|