mirror of
https://github.com/cubixle/playground.git
synced 2026-04-24 21:24:43 +01:00
add LRU Cache
This commit is contained in:
24
lru/coverage.out
Normal file
24
lru/coverage.out
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
mode: set
|
||||||
|
github.com/cubixle/lru/lru.go:11.31,17.2 1 1
|
||||||
|
github.com/cubixle/lru/lru.go:19.40,21.9 2 1
|
||||||
|
github.com/cubixle/lru/lru.go:21.9,23.3 1 0
|
||||||
|
github.com/cubixle/lru/lru.go:25.2,25.14 1 1
|
||||||
|
github.com/cubixle/lru/lru.go:25.14,27.3 1 0
|
||||||
|
github.com/cubixle/lru/lru.go:29.2,29.15 1 1
|
||||||
|
github.com/cubixle/lru/lru.go:32.38,34.9 2 1
|
||||||
|
github.com/cubixle/lru/lru.go:34.9,39.23 3 1
|
||||||
|
github.com/cubixle/lru/lru.go:39.23,46.4 4 1
|
||||||
|
github.com/cubixle/lru/lru.go:48.3,48.9 1 1
|
||||||
|
github.com/cubixle/lru/lru.go:51.2,52.23 2 0
|
||||||
|
github.com/cubixle/lru/lru.go:68.22,70.2 1 1
|
||||||
|
github.com/cubixle/lru/lru.go:72.37,73.19 1 1
|
||||||
|
github.com/cubixle/lru/lru.go:73.19,78.3 3 1
|
||||||
|
github.com/cubixle/lru/lru.go:80.2,85.39 5 1
|
||||||
|
github.com/cubixle/lru/lru.go:88.50,97.2 3 1
|
||||||
|
github.com/cubixle/lru/lru.go:99.32,100.14 1 1
|
||||||
|
github.com/cubixle/lru/lru.go:100.14,102.3 1 0
|
||||||
|
github.com/cubixle/lru/lru.go:104.2,108.17 4 1
|
||||||
|
github.com/cubixle/lru/lru.go:108.17,110.3 1 0
|
||||||
|
github.com/cubixle/lru/lru.go:113.29,116.2 2 1
|
||||||
|
github.com/cubixle/lru/lru.go:118.24,120.18 2 1
|
||||||
|
github.com/cubixle/lru/lru.go:120.18,123.3 2 1
|
||||||
3
lru/go.mod
Normal file
3
lru/go.mod
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module github.com/cubixle/lru
|
||||||
|
|
||||||
|
go 1.21.6
|
||||||
121
lru/lru.go
Normal file
121
lru/lru.go
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
package lru
|
||||||
|
|
||||||
|
import "log"
|
||||||
|
|
||||||
|
type Cache struct {
|
||||||
|
cap int
|
||||||
|
m map[string]*node
|
||||||
|
l *list
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCache(cap int) *Cache {
|
||||||
|
return &Cache{
|
||||||
|
cap: cap,
|
||||||
|
m: make(map[string]*node, 2),
|
||||||
|
l: newList(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) Get(key string) string {
|
||||||
|
v, ok := c.m[key]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if v == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) Set(key, val string) {
|
||||||
|
node, ok := c.m[key]
|
||||||
|
if !ok {
|
||||||
|
node := c.l.pushFront(key, val)
|
||||||
|
|
||||||
|
c.m[key] = node
|
||||||
|
|
||||||
|
if len(c.m) > c.cap {
|
||||||
|
n := c.l.back()
|
||||||
|
c.l.remove(n)
|
||||||
|
delete(c.m, n.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
node.data = val
|
||||||
|
c.l.moveToFront(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
type node struct {
|
||||||
|
key string
|
||||||
|
data string
|
||||||
|
next *node
|
||||||
|
prev *node
|
||||||
|
}
|
||||||
|
|
||||||
|
type list struct {
|
||||||
|
head *node
|
||||||
|
}
|
||||||
|
|
||||||
|
func newList() *list {
|
||||||
|
return &list{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *list) moveToFront(n *node) {
|
||||||
|
if l.head == nil {
|
||||||
|
n.prev = l.head
|
||||||
|
l.head = n
|
||||||
|
l.head.prev = n
|
||||||
|
} else {
|
||||||
|
n.next = l.head
|
||||||
|
n.prev = l.head.prev
|
||||||
|
l.head.prev = n
|
||||||
|
l.head = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *list) pushFront(key, data string) *node {
|
||||||
|
n := &node{
|
||||||
|
key: key,
|
||||||
|
data: data,
|
||||||
|
}
|
||||||
|
|
||||||
|
l.moveToFront(n)
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *list) remove(n *node) {
|
||||||
|
if n == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
n.prev.next = n.next
|
||||||
|
if n.next != nil {
|
||||||
|
n.next.prev = n.prev
|
||||||
|
}
|
||||||
|
|
||||||
|
n = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *list) back() *node {
|
||||||
|
return l.head.prev
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *list) debug() {
|
||||||
|
log.Println("--------")
|
||||||
|
start := l.head.data
|
||||||
|
node := l.head
|
||||||
|
for node != nil {
|
||||||
|
log.Println(node)
|
||||||
|
|
||||||
|
node = node.next
|
||||||
|
if node != nil && node.data == start {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Println("--------")
|
||||||
|
}
|
||||||
35
lru/lru_test.go
Normal file
35
lru/lru_test.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package lru_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cubixle/lru"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCache(t *testing.T) {
|
||||||
|
cache := lru.NewCache(2)
|
||||||
|
cache.Set("usa", "washington")
|
||||||
|
cache.Set("uk", "london")
|
||||||
|
|
||||||
|
city := cache.Get("usa")
|
||||||
|
if city != "washington" {
|
||||||
|
t.Fatal("didn't get the correct city for usa")
|
||||||
|
}
|
||||||
|
|
||||||
|
city = cache.Get("uk")
|
||||||
|
if city != "london" {
|
||||||
|
t.Fatal("didn't get the correct city for uk")
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.Set("france", "paris")
|
||||||
|
|
||||||
|
city = cache.Get("france")
|
||||||
|
if city != "paris" {
|
||||||
|
t.Fatal("didn't get the correct city for uk")
|
||||||
|
}
|
||||||
|
|
||||||
|
city = cache.Get("usa")
|
||||||
|
if city != "" {
|
||||||
|
t.Fatal("usa is still in the cache but should have been removed")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user