/** * Standalone signaling server for the Nextcloud Spreed app. * Copyright (C) 2017 struktur AG * * @author Joachim Bauch * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ package container import ( "container/list" "sync" ) type cacheEntry[T any] struct { key string value T } type LruCache[T any] struct { size int // +checklocksignore: Only written to from constructor. mu sync.Mutex // +checklocks:mu entries *list.List // +checklocks:mu data map[string]*list.Element } func NewLruCache[T any](size int) *LruCache[T] { return &LruCache[T]{ size: size, entries: list.New(), data: make(map[string]*list.Element), } } func (c *LruCache[T]) Set(key string, value T) { c.mu.Lock() if v, found := c.data[key]; found { c.entries.MoveToFront(v) v.Value.(*cacheEntry[T]).value = value c.mu.Unlock() return } v := c.entries.PushFront(&cacheEntry[T]{ key: key, value: value, }) c.data[key] = v if c.size > 0 && c.entries.Len() > c.size { c.removeOldestLocked() } c.mu.Unlock() } func (c *LruCache[T]) Get(key string) T { c.mu.Lock() if v, found := c.data[key]; found { c.entries.MoveToFront(v) value := v.Value.(*cacheEntry[T]).value c.mu.Unlock() return value } c.mu.Unlock() var defaultValue T return defaultValue } func (c *LruCache[T]) Remove(key string) { c.mu.Lock() if v, found := c.data[key]; found { c.removeElement(v) } c.mu.Unlock() } // +checklocks:c.mu func (c *LruCache[T]) removeOldestLocked() { v := c.entries.Back() if v != nil { c.removeElement(v) } } func (c *LruCache[T]) RemoveOldest() { c.mu.Lock() c.removeOldestLocked() c.mu.Unlock() } // +checklocks:c.mu func (c *LruCache[T]) removeElement(e *list.Element) { c.entries.Remove(e) entry := e.Value.(*cacheEntry[T]) delete(c.data, entry.key) } func (c *LruCache[T]) Len() int { c.mu.Lock() defer c.mu.Unlock() return c.entries.Len() }