-
Notifications
You must be signed in to change notification settings - Fork 0
/
lru.go
162 lines (140 loc) · 3.23 KB
/
lru.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package lru
import (
"container/list"
"errors"
"sync"
)
type EvictCallback func(key interface{}, value interface{})
type Cache struct {
size int
evictList *list.List
//items map[interface{}]*list.Element
items *sync.Map
onEvict EvictCallback
}
type entry struct {
key interface{}
value interface{}
}
func NewCache(size int, onEvict EvictCallback) (*Cache, error) {
if size <= 0 {
return nil, errors.New("must provide a positive size")
}
c := &Cache{
size: size,
evictList: list.New(),
items: &sync.Map{},
onEvict: onEvict,
}
return c, nil
}
func (c *Cache) Purge() {
c.items.Range(func(k, v any) bool {
if c.onEvict != nil {
c.onEvict(k, v.(*list.Element).Value.(*entry).value)
}
c.items.Delete(k)
return true
})
c.evictList.Init()
}
func (c *Cache) Add(key, value interface{}) (evicted bool) {
if v, ok := c.items.Load(key); ok {
ent := v.(*list.Element)
c.evictList.MoveToFront(ent)
ent.Value.(*entry).value = value
}
ent := &entry{key, value}
entry_ := c.evictList.PushFront(ent)
c.items.Store(key, entry_)
evict := c.evictList.Len() > c.size
if evict {
c.removeOldest()
}
return evict
}
func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
if v, ok_ := c.items.Load(key); ok_ {
ent := v.(*list.Element)
c.evictList.MoveToFront(ent)
return ent.Value.(*entry).value, true
}
return
}
func (c *Cache) Contains(key interface{}) (ok bool) {
_, ok = c.items.Load(key)
return ok
}
func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) {
if v, ok_ := c.items.Load(key); ok_ {
ent := v.(*list.Element)
return ent.Value.(*entry).value, true
}
return nil, false
}
func (c *Cache) Remove(key interface{}) (present bool) {
if v, ok_ := c.items.Load(key); ok_ {
ent := v.(*list.Element)
c.removeElement(ent, true)
return true
}
return false
}
func (c *Cache) RemoveWithoutCallback(key interface{}) (present bool) {
if v, ok_ := c.items.Load(key); ok_ {
ent := v.(*list.Element)
c.removeElement(ent, false)
return true
}
return false
}
func (c *Cache) RemoveOldest() (key interface{}, value interface{}, ok bool) {
ent := c.evictList.Back()
if ent != nil {
c.removeElement(ent, true)
kv := ent.Value.(*entry)
return kv.key, kv.value, true
}
return nil, nil, false
}
func (c *Cache) GetOldest() (key interface{}, value interface{}, ok bool) {
ent := c.evictList.Back()
if ent != nil {
kv := ent.Value.(*entry)
return kv.key, kv.value, true
}
return nil, nil, false
}
func (c *Cache) Keys() []interface{} {
var keys []interface{}
i := 0
for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() {
keys[i] = ent.Value.(*entry).key
i++
}
return keys
}
func (c *Cache) Len() int {
return c.evictList.Len()
}
func (c *Cache) removeOldest() {
ent := c.evictList.Back()
if ent != nil {
c.removeElement(ent, true)
}
}
func (c *Cache) removeElement(e *list.Element, needEvictCallback bool) {
c.evictList.Remove(e)
kv := e.Value.(*entry)
c.items.Delete(kv.key)
if needEvictCallback && c.onEvict != nil {
c.onEvict(kv.key, kv.value)
}
}
func (c *Cache) ForEach(callback func(value interface{})) {
c.items.Range(func(key, value any) bool {
ent := value.(*list.Element)
callback(ent.Value.(*entry).value)
return true
})
}