Skip to content

Instantly share code, notes, and snippets.

@illarion
Created April 6, 2022 19:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save illarion/7fb8e7ee0b302546a3685d026f02f894 to your computer and use it in GitHub Desktop.
Save illarion/7fb8e7ee0b302546a3685d026f02f894 to your computer and use it in GitHub Desktop.
simple LRU cache impl
package cache
import (
"container/list"
"sync"
)
type listData[K comparable, V any] struct {
key K
data V
}
type Cache[K comparable, V any] struct {
mu sync.Mutex
mapping map[K]*list.Element
lst *list.List
size int
get func(K) (V, error)
}
func New[K comparable, V any](size int, get func(K) (V, error)) *Cache[K, V] {
return &Cache[K, V]{
mapping: make(map[K]*list.Element),
lst: list.New(),
size: size,
get: get,
}
}
func (t *Cache[K, V]) Get(key K) (V, error) {
t.mu.Lock()
defer t.mu.Unlock()
if element, ok := t.mapping[key]; ok {
//cache hit
t.lst.MoveToFront(element)
if value, ok := element.Value.(listData[K, V]); ok {
return value.data, nil
} else {
panic("could not convert")
}
}
//cache miss, load from getter function
value, err := t.get(key)
if err != nil {
var zero V
return zero, err
}
//evict
if t.lst.Len() >= t.size {
toEvict := t.lst.Back()
data, ok := toEvict.Value.(listData[K, V])
if !ok {
panic("Could not convert")
}
delete(t.mapping, data.key)
t.lst.Remove(toEvict)
}
//insert
element := t.lst.PushFront(listData[K, V]{key, value})
t.mapping[key] = element
return value, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment