package lru import ( "container/list" "time" ) type LRU[T any] struct { queue *list.List items map[string]*list.Element capacity int } type item[T any] struct { key string value T eol time.Time } func New[T any](capacity int) *LRU[T] { return &LRU[T]{ queue: list.New(), items: make(map[string]*list.Element, capacity), capacity: capacity, } } func (lru *LRU[T]) Set(key string, value T, ttl time.Duration) (evicted bool) { eol := time.Now().Add(ttl) if element, ok := lru.items[key]; ok { lru.queue.MoveToFront(element) item := element.Value.(*item[T]) item.value = value item.eol = eol return } if lru.queue.Len() == lru.capacity { lru.evict() evicted = true } item := &item[T]{ key: key, value: value, eol: eol, } element := lru.queue.PushFront(item) lru.items[item.key] = element return } func (lru *LRU[T]) Get(name string) (value T, ok bool) { element, ok := lru.items[name] if !ok { return value, false } item := element.Value.(*item[T]) if item.expired() { lru.delete(element) return value, false } lru.queue.MoveToFront(element) return item.value, true } func (lru *LRU[T]) evict() { element := lru.queue.Back() if element == nil { return } for { // find first expired item := element.Value.(*item[T]) if item.expired() { lru.delete(element) return } element = element.Prev() if element == nil { break // probably expired not found } } lru.delete(lru.queue.Back()) // delete oldest if no one expired } func (lru *LRU[T]) delete(element *list.Element) { lru.queue.Remove(element) delete(lru.items, element.Value.(*item[T]).key) } func (i *item[T]) expired() bool { return time.Now().After(i.eol) }