github.com/EagleQL/Xray-core@v1.4.3/common/cache/lru.go (about) 1 package cache 2 3 import ( 4 "container/list" 5 sync "sync" 6 ) 7 8 // Lru simple, fast lru cache implementation 9 type Lru interface { 10 Get(key interface{}) (value interface{}, ok bool) 11 GetKeyFromValue(value interface{}) (key interface{}, ok bool) 12 PeekKeyFromValue(value interface{}) (key interface{}, ok bool) // Peek means check but NOT bring to top 13 Put(key, value interface{}) 14 } 15 16 type lru struct { 17 capacity int 18 doubleLinkedlist *list.List 19 keyToElement *sync.Map 20 valueToElement *sync.Map 21 mu *sync.Mutex 22 } 23 24 type lruElement struct { 25 key interface{} 26 value interface{} 27 } 28 29 // NewLru init a lru cache 30 func NewLru(cap int) Lru { 31 return lru{ 32 capacity: cap, 33 doubleLinkedlist: list.New(), 34 keyToElement: new(sync.Map), 35 valueToElement: new(sync.Map), 36 mu: new(sync.Mutex), 37 } 38 } 39 40 func (l lru) Get(key interface{}) (value interface{}, ok bool) { 41 if v, ok := l.keyToElement.Load(key); ok { 42 element := v.(*list.Element) 43 l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front()) 44 return element.Value.(lruElement).value, true 45 } 46 return nil, false 47 } 48 49 func (l lru) GetKeyFromValue(value interface{}) (key interface{}, ok bool) { 50 if k, ok := l.valueToElement.Load(value); ok { 51 element := k.(*list.Element) 52 l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front()) 53 return element.Value.(lruElement).key, true 54 } 55 return nil, false 56 } 57 58 func (l lru) PeekKeyFromValue(value interface{}) (key interface{}, ok bool) { 59 if k, ok := l.valueToElement.Load(value); ok { 60 element := k.(*list.Element) 61 return element.Value.(lruElement).key, true 62 } 63 return nil, false 64 } 65 66 func (l lru) Put(key, value interface{}) { 67 e := lruElement{key, value} 68 if v, ok := l.keyToElement.Load(key); ok { 69 element := v.(*list.Element) 70 element.Value = e 71 l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front()) 72 } else { 73 l.mu.Lock() 74 element := l.doubleLinkedlist.PushFront(e) 75 l.keyToElement.Store(key, element) 76 l.valueToElement.Store(value, element) 77 if l.doubleLinkedlist.Len() > l.capacity { 78 toBeRemove := l.doubleLinkedlist.Back() 79 l.doubleLinkedlist.Remove(toBeRemove) 80 l.keyToElement.Delete(toBeRemove.Value.(lruElement).key) 81 l.valueToElement.Delete(toBeRemove.Value.(lruElement).value) 82 } 83 l.mu.Unlock() 84 } 85 }