-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlfu.go
148 lines (125 loc) · 2.65 KB
/
lfu.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
// Package lfu is Least Frequently Used Cache with all the operations in O(1).
package lfu
import "sync"
type freqNode[K comparable, V any] struct {
value int
items map[K]struct{}
prev *freqNode[K, V]
next *freqNode[K, V]
}
func newFrequencyNode[K comparable, V any]() *freqNode[K, V] {
n := &freqNode[K, V]{
items: make(map[K]struct{}),
}
n.prev = n
n.next = n
return n
}
type item[K comparable, V any] struct {
data V
parent *freqNode[K, V]
}
func newItem[K comparable, V any](data V, parent *freqNode[K, V]) *item[K, V] {
return &item[K, V]{
data: data,
parent: parent,
}
}
// Cache structure.
type Cache[K comparable, V any] struct {
mu sync.RWMutex
length int
maxLength int
byKey map[K]*item[K, V]
freq *freqNode[K, V]
}
// NewCache creates a new cache.
func NewCache[K comparable, V any](size int) *Cache[K, V] {
return &Cache[K, V]{
maxLength: size,
byKey: make(map[K]*item[K, V]),
freq: newFrequencyNode[K, V](),
}
}
// Get gets an element.
func (c *Cache[K, V]) Get(k K) (V, bool) {
c.mu.Lock()
defer c.mu.Unlock()
var zero V
tmp, exists := c.byKey[k]
if !exists {
return zero, false
}
freq := tmp.parent
nextFreq := freq.next
if nextFreq == c.freq || nextFreq.value != freq.value+1 {
nextFreq = getNewNode(freq.value+1, freq, nextFreq)
}
nextFreq.items[k] = struct{}{}
tmp.parent = nextFreq
delete(freq.items, k)
if len(freq.items) == 0 {
deleteNode(freq)
}
return tmp.data, true
}
// Set inserts an element.
func (c *Cache[K, V]) Set(k K, v V) {
c.mu.Lock()
defer c.mu.Unlock()
if freq, exists := c.byKey[k]; exists {
freq.data = v
return
}
c.length++
if c.length > c.maxLength {
c.deleteLFU()
c.length--
}
freq := c.freq.next
if freq.value != 1 {
freq = getNewNode(1, c.freq, freq)
}
freq.items[k] = struct{}{}
c.byKey[k] = newItem(v, freq)
}
// GetLFU gets the least frequently used key.
func (c *Cache[K, _]) GetLFU() (K, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
var zero K
if len(c.byKey) == 0 {
return zero, false
}
for k := range c.freq.next.items {
return k, true
}
panic("no element")
}
func (c *Cache[K, _]) deleteLFU() {
var key K
head := c.freq.next
for k := range head.items {
key = k
break
}
if len(head.items) == 1 {
c.freq.next = c.freq.next.next
} else {
delete(head.items, key)
}
delete(c.byKey, key)
}
func getNewNode[K comparable, V any](value int, prev, next *freqNode[K, V]) *freqNode[K, V] {
n := newFrequencyNode[K, V]()
n.value = value
n.prev = prev
n.next = next
prev.next = n
next.prev = n
return n
}
func deleteNode[K comparable, V any](n *freqNode[K, V]) {
n.prev.next = n.next
n.next.prev = n.prev
}