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:
@@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user