github.com/andy2046/gopie@v0.7.0/pkg/lru/lru.go (about) 1 // Package lru implements a LRU cache. 2 package lru 3 4 import ( 5 "container/list" 6 "sync" 7 ) 8 9 // Cache is a LRU cache. 10 type Cache struct { 11 // MaxEntries is the maximum number of cache entries 12 // before an item is purged. Zero means no limit. 13 MaxEntries int 14 15 // OnPurged specifies a function to be executed 16 // when an entry is purged from the cache. 17 OnPurged func(key interface{}, value interface{}) 18 19 ll *list.List 20 cache map[interface{}]*list.Element 21 mu sync.RWMutex 22 } 23 24 type entry struct { 25 key interface{} 26 value interface{} 27 } 28 29 // New creates a new cache, if maxEntries is zero, the cache has no limit. 30 func New(maxEntries int) *Cache { 31 if maxEntries < 0 { 32 panic("maxEntries can not be less than zero") 33 } 34 return &Cache{ 35 MaxEntries: maxEntries, 36 ll: list.New(), 37 cache: make(map[interface{}]*list.Element), 38 } 39 } 40 41 // Add adds value to the cache. 42 func (c *Cache) Add(key interface{}, value interface{}) { 43 c.mu.Lock() 44 defer c.mu.Unlock() 45 46 if c.cache == nil { 47 c.cache = make(map[interface{}]*list.Element) 48 c.ll = list.New() 49 } 50 if e, ok := c.cache[key]; ok { 51 c.ll.MoveToFront(e) 52 e.Value.(*entry).value = value 53 return 54 } 55 ele := c.ll.PushFront(&entry{key, value}) 56 c.cache[key] = ele 57 if c.MaxEntries > 0 && c.ll.Len() > c.MaxEntries { 58 c.removeOldest(false) 59 } 60 } 61 62 // Get looks up value by key from the cache. 63 func (c *Cache) Get(key interface{}) (value interface{}, ok bool) { 64 c.mu.Lock() 65 defer c.mu.Unlock() 66 67 if c.cache == nil { 68 return 69 } 70 if ele, hit := c.cache[key]; hit { 71 c.ll.MoveToFront(ele) 72 return ele.Value.(*entry).value, true 73 } 74 return 75 } 76 77 // Remove removes the provided key from the cache. 78 func (c *Cache) Remove(key interface{}) { 79 c.mu.Lock() 80 defer c.mu.Unlock() 81 82 if c.cache == nil { 83 return 84 } 85 if ele, hit := c.cache[key]; hit { 86 c.removeElement(ele) 87 } 88 } 89 90 // RemoveOldest removes the oldest item from the cache. 91 func (c *Cache) RemoveOldest() { 92 c.removeOldest(true) 93 } 94 95 func (c *Cache) removeOldest(toLock bool) { 96 if toLock { 97 c.mu.Lock() 98 defer c.mu.Unlock() 99 } 100 101 if c.cache == nil { 102 return 103 } 104 ele := c.ll.Back() 105 if ele != nil { 106 c.removeElement(ele) 107 } 108 } 109 110 func (c *Cache) removeElement(e *list.Element) { 111 c.ll.Remove(e) 112 kv := e.Value.(*entry) 113 delete(c.cache, kv.key) 114 if c.OnPurged != nil { 115 c.OnPurged(kv.key, kv.value) 116 } 117 } 118 119 // Len returns the number of items in the cache. 120 func (c *Cache) Len() int { 121 c.mu.RLock() 122 defer c.mu.RUnlock() 123 124 if c.cache == nil { 125 return 0 126 } 127 return c.ll.Len() 128 } 129 130 // Clear purges all items from the cache. 131 func (c *Cache) Clear() { 132 c.mu.Lock() 133 defer c.mu.Unlock() 134 135 if c.OnPurged != nil { 136 for _, e := range c.cache { 137 kv := e.Value.(*entry) 138 c.OnPurged(kv.key, kv.value) 139 } 140 } 141 c.ll = nil 142 c.cache = nil 143 }