1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-15 18:22:27 +08:00

fix: fix lru cache bug

This commit is contained in:
dudaodong
2022-03-14 11:19:30 +08:00
parent 78519088ab
commit 569902b528
2 changed files with 53 additions and 33 deletions

View File

@@ -17,7 +17,7 @@ func newLruNode[K comparable, V any](key K, value V) *lruNode[K, V] {
} }
} }
// LRUCache lru cache // LRUCache lru cache (thread unsafe)
type LRUCache[K comparable, V any] struct { type LRUCache[K comparable, V any] struct {
cache map[K]*lruNode[K, V] cache map[K]*lruNode[K, V]
head *lruNode[K, V] head *lruNode[K, V]
@@ -29,7 +29,7 @@ type LRUCache[K comparable, V any] struct {
// NewLRUCache return a LRUCache pointer // NewLRUCache return a LRUCache pointer
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] { func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
return &LRUCache[K, V]{ return &LRUCache[K, V]{
cache: make(map[K]*lruNode[K, V]), cache: make(map[K]*lruNode[K, V], capacity),
head: nil, head: nil,
tail: nil, tail: nil,
capacity: capacity, capacity: capacity,
@@ -42,58 +42,61 @@ func (l *LRUCache[K, V]) Get(key K) (V, bool) {
var value V var value V
node, ok := l.cache[key] node, ok := l.cache[key]
if node == nil || !ok { if ok {
return value, false l.moveToHead(node)
return node.value, true
} }
l.moveToHead(node) return value, false
return node.value, true
} }
// Put value of key into lru cache // Put value of key into lru cache
func (l *LRUCache[K, V]) Put(key K, value V) { func (l *LRUCache[K, V]) Put(key K, value V) {
node, ok := l.cache[key] node, ok := l.cache[key]
if node == nil || !ok { if !ok {
newNode := newLruNode(key, value) newNode := newLruNode(key, value)
l.cache[key] = newNode l.cache[key] = newNode
l.addNode(newNode) l.addNode(newNode)
l.length++ if len(l.cache) > l.capacity {
if l.length > l.capacity { oldKey := l.deleteNode(l.head)
tail := l.popTail() delete(l.cache, oldKey)
delete(l.cache, tail.key)
l.length--
} }
} else {
node.value = value
l.moveToHead(node)
} }
l.length = len(l.cache)
node.value = value
l.moveToHead(node)
} }
func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) { func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) {
node.pre = l.head if l.tail != nil {
node.next = l.head.next l.tail.next = node
node.pre = l.tail
l.head.next.pre = node node.next = nil
l.head.next = node }
l.tail = node
if l.head == nil {
l.head = node
}
} }
func (l *LRUCache[K, V]) deleteNode(node *lruNode[K, V]) { func (l *LRUCache[K, V]) deleteNode(node *lruNode[K, V]) K {
pre := node.pre if node == l.tail {
next := node.next l.tail = l.tail.pre
} else if node == l.head {
pre.next = next l.head = l.head.next
next.pre = pre } else {
node.pre.next = node.next
node.next.pre = node.pre
}
return node.key
} }
func (l *LRUCache[K, V]) moveToHead(node *lruNode[K, V]) { func (l *LRUCache[K, V]) moveToHead(node *lruNode[K, V]) {
if l.tail == node {
return
}
l.deleteNode(node) l.deleteNode(node)
l.addNode(node) l.addNode(node)
} }
func (l *LRUCache[K, V]) popTail() *lruNode[K, V] {
node := l.tail.pre
l.deleteNode(node)
return node
}

View File

@@ -16,4 +16,21 @@ func TestLRUCache(t *testing.T) {
_, ok := cache.Get(0) _, ok := cache.Get(0)
asssert.Equal(false, ok) asssert.Equal(false, ok)
v, ok := cache.Get(1)
asssert.Equal(true, ok)
asssert.Equal(1, v)
v, ok = cache.Get(2)
asssert.Equal(true, ok)
asssert.Equal(2, v)
cache.Put(3, 3)
v, ok = cache.Get(1)
asssert.Equal(false, ok)
asssert.NotEqual(1, v)
v, ok = cache.Get(3)
asssert.Equal(true, ok)
asssert.Equal(3, v)
} }