Hunter0x7c7
2022-08-11 a82f9cb69f63aaeba40c024960deda7d75b9fece
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
package cache
 
import (
    "container/list"
    "sync"
)
 
// Lru simple, fast lru cache implementation
type Lru interface {
    Get(key interface{}) (value interface{}, ok bool)
    GetKeyFromValue(value interface{}) (key interface{}, ok bool)
    Put(key, value interface{})
}
 
type lru struct {
    capacity         int
    doubleLinkedlist *list.List
    keyToElement     *sync.Map
    valueToElement   *sync.Map
    mu               *sync.Mutex
}
 
type lruElement struct {
    key   interface{}
    value interface{}
}
 
// NewLru initializes a lru cache
func NewLru(cap int) Lru {
    return &lru{
        capacity:         cap,
        doubleLinkedlist: list.New(),
        keyToElement:     new(sync.Map),
        valueToElement:   new(sync.Map),
        mu:               new(sync.Mutex),
    }
}
 
func (l *lru) Get(key interface{}) (value interface{}, ok bool) {
    l.mu.Lock()
    defer l.mu.Unlock()
    if v, ok := l.keyToElement.Load(key); ok {
        element := v.(*list.Element)
        l.doubleLinkedlist.MoveToFront(element)
        return element.Value.(*lruElement).value, true
    }
    return nil, false
}
 
func (l *lru) GetKeyFromValue(value interface{}) (key interface{}, ok bool) {
    l.mu.Lock()
    defer l.mu.Unlock()
    if k, ok := l.valueToElement.Load(value); ok {
        element := k.(*list.Element)
        l.doubleLinkedlist.MoveToFront(element)
        return element.Value.(*lruElement).key, true
    }
    return nil, false
}
 
func (l *lru) Put(key, value interface{}) {
    l.mu.Lock()
    e := &lruElement{key, value}
    if v, ok := l.keyToElement.Load(key); ok {
        element := v.(*list.Element)
        element.Value = e
        l.doubleLinkedlist.MoveToFront(element)
    } else {
        element := l.doubleLinkedlist.PushFront(e)
        l.keyToElement.Store(key, element)
        l.valueToElement.Store(value, element)
        if l.doubleLinkedlist.Len() > l.capacity {
            toBeRemove := l.doubleLinkedlist.Back()
            l.doubleLinkedlist.Remove(toBeRemove)
            l.keyToElement.Delete(toBeRemove.Value.(*lruElement).key)
            l.valueToElement.Delete(toBeRemove.Value.(*lruElement).value)
        }
    }
    l.mu.Unlock()
}