Skip to content

Instantly share code, notes, and snippets.

@lub0s
Created May 20, 2024 19:55
Show Gist options
  • Save lub0s/dec46f45c458a8b303100d2f61fdf7e6 to your computer and use it in GitHub Desktop.
Save lub0s/dec46f45c458a8b303100d2f61fdf7e6 to your computer and use it in GitHub Desktop.
package cache
import (
"container/list"
"sync"
)
type Cache[K comparable, V any] interface {
Get(key K) V
Put(key K, value V) V
Delete(key K)
}
type CacheEntry[K comparable, V any] struct {
key K
value V
}
type Lru[K comparable, V any] struct {
mut sync.RWMutex
access *list.List
keyed map[K]*list.Element
maxSize int
}
func NewLru[K comparable, V any](maxSize int) Cache[K, V] {
return &Lru[K, V]{
access: list.New(),
keyed: make(map[K]*list.Element, maxSize),
maxSize: maxSize,
}
}
func getZero[T any]() T {
var result T
return result
}
func (c *Lru[K, V]) Get(key K) V {
c.mut.RLock()
defer c.mut.RUnlock()
found := c.keyed[key]
if found == nil {
return getZero[V]()
}
c.access.MoveToFront(found)
return found.Value.(*CacheEntry[K, V]).value
}
func (c *Lru[K, V]) Put(key K, value V) V {
c.mut.Lock()
defer c.mut.Unlock()
found := c.keyed[key]
// override existing value if found
if found != nil {
c.access.MoveToFront(found)
if front := c.access.Front(); front != nil {
entry := found.Value.(*CacheEntry[K, V])
entry.value = value
}
return value
}
entry := &CacheEntry[K, V]{
key: key,
value: value,
}
if len(c.keyed) == c.maxSize {
oldest := c.access.Remove(c.access.Back()).(*CacheEntry[K, V])
delete(c.keyed, oldest.key)
}
c.keyed[key] = c.access.PushFront(entry)
return value
}
func (c *Lru[K, V]) Delete(key K) {
c.mut.Lock()
defer c.mut.Unlock()
found := c.keyed[key]
if found != nil {
c.access.Remove(found)
delete(c.keyed, key)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment