Skip to content

Commit f9cb08b

Browse files
committed
added first lru cache commit
1 parent 2db8578 commit f9cb08b

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed

lru/example_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package lru_test
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/Code-Hex/go-generics-cache/lru"
7+
)
8+
9+
func ExampleLRUCache() {
10+
c := lru.New[string, int]()
11+
c.Set("a", 1)
12+
c.Set("b", 2)
13+
av, aok := c.Get("a")
14+
bv, bok := c.Get("b")
15+
cv, cok := c.Get("c")
16+
fmt.Println(av, aok)
17+
fmt.Println(bv, bok)
18+
fmt.Println(cv, cok)
19+
// Output:
20+
// 1 true
21+
// 2 true
22+
// 0 false
23+
}
24+
25+
func ExampleCacheKeys() {
26+
c := lru.New[string, int]()
27+
c.Set("a", 1)
28+
c.Set("b", 2)
29+
c.Set("c", 3)
30+
keys := c.Keys()
31+
for _, key := range keys {
32+
fmt.Println(key)
33+
}
34+
// Output:
35+
// a
36+
// b
37+
// c
38+
}

lru/lru.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package lru
2+
3+
import (
4+
"container/list"
5+
"sync"
6+
)
7+
8+
// Cache is a thread safe LRU cache
9+
type Cache[K comparable, V any] struct {
10+
cap int
11+
list *list.List
12+
items map[K]*list.Element
13+
mu sync.RWMutex
14+
}
15+
16+
type item[K comparable, V any] struct {
17+
Key K
18+
Value V
19+
}
20+
21+
// New creates a new LRU cache whose capacity is the default size (128).
22+
func New[K comparable, V any]() *Cache[K, V] {
23+
return NewCap[K, V](128)
24+
}
25+
26+
// NewCap creates a new LRU cache whose capacity is the specified size.
27+
func NewCap[K comparable, V any](cap int) *Cache[K, V] {
28+
return &Cache[K, V]{
29+
cap: cap,
30+
list: list.New(),
31+
items: make(map[K]*list.Element),
32+
}
33+
}
34+
35+
// Get looks up a key's value from the cache.
36+
func (c *Cache[K, V]) Get(key K) (zero V, _ bool) {
37+
c.mu.RLock()
38+
defer c.mu.RUnlock()
39+
if e, ok := c.items[key]; ok {
40+
// updates cache order
41+
c.list.MoveToFront(e)
42+
return e.Value.(*item[K, V]).Value, true
43+
}
44+
return
45+
}
46+
47+
// Set sets a value to the cache with key. replacing any existing value.
48+
func (c *Cache[K, V]) Set(key K, val V) {
49+
c.mu.Lock()
50+
defer c.mu.Unlock()
51+
if e, ok := c.items[key]; ok {
52+
// updates cache order
53+
c.list.MoveToFront(e)
54+
e.Value = val
55+
return
56+
}
57+
58+
e := c.list.PushFront(&item[K, V]{
59+
Key: key,
60+
Value: val,
61+
})
62+
c.items[key] = e
63+
64+
if c.list.Len() > c.cap {
65+
c.deleteOldest()
66+
}
67+
}
68+
69+
// Keys returns the keys of the cache. the order is from oldest to newest.
70+
func (c *Cache[K, V]) Keys() []K {
71+
c.mu.RLock()
72+
defer c.mu.RUnlock()
73+
74+
keys := make([]K, 0, len(c.items))
75+
for ent := c.list.Back(); ent != nil; ent = ent.Prev() {
76+
keys = append(keys, ent.Value.(*item[K, V]).Key)
77+
}
78+
return keys
79+
}
80+
81+
// Len returns the number of items in the cache.
82+
func (c *Cache[K, V]) Len() int {
83+
c.mu.RLock()
84+
defer c.mu.RLock()
85+
return c.list.Len()
86+
}
87+
88+
// Delete deletes the item with provided key from the cache.
89+
func (c *Cache[K, V]) Delete(key K) {
90+
c.mu.Lock()
91+
defer c.mu.Unlock()
92+
if e, ok := c.items[key]; ok {
93+
c.delete(e)
94+
}
95+
}
96+
97+
// Contains reports whether key is within cache.
98+
func (c *Cache[K, V]) Contains(key K) bool {
99+
c.mu.RLock()
100+
defer c.mu.RUnlock()
101+
_, ok := c.items[key]
102+
return ok
103+
}
104+
105+
func (c *Cache[K, V]) deleteOldest() {
106+
e := c.list.Back()
107+
c.delete(e)
108+
}
109+
110+
func (c *Cache[K, V]) delete(e *list.Element) {
111+
c.list.Remove(e)
112+
item := e.Value.(*item[K, V])
113+
delete(c.items, item.Key)
114+
}

0 commit comments

Comments
 (0)