|
| 1 | +package lru |
| 2 | + |
| 3 | +import "container/list" |
| 4 | + |
| 5 | +// Cache is a LRU cache. It is not safe for concurrent access. |
| 6 | +type Cache struct { |
| 7 | + maxBytes int64 |
| 8 | + nbytes int64 |
| 9 | + ll *list.List |
| 10 | + cache map[string]*list.Element |
| 11 | + // optional and executed when an entry is purged. |
| 12 | + OnEvicted func(key string, value Value) |
| 13 | +} |
| 14 | + |
| 15 | +type entry struct { |
| 16 | + key string |
| 17 | + value Value |
| 18 | +} |
| 19 | + |
| 20 | +// Value use Len to count how many bytes it takes |
| 21 | +type Value interface { |
| 22 | + Len() int |
| 23 | +} |
| 24 | + |
| 25 | +// New is the Constructor of Cache |
| 26 | +func New(maxBytes int64, onEvicted func(string, Value)) *Cache { |
| 27 | + return &Cache{ |
| 28 | + maxBytes: maxBytes, |
| 29 | + ll: list.New(), |
| 30 | + cache: make(map[string]*list.Element), |
| 31 | + OnEvicted: onEvicted, |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +// Add adds a value to the cache. |
| 36 | +func (c *Cache) Add(key string, value Value) { |
| 37 | + if ele, ok := c.cache[key]; ok { |
| 38 | + c.ll.MoveToFront(ele) |
| 39 | + kv := ele.Value.(*entry) |
| 40 | + c.nbytes += int64(value.Len()) - int64(kv.value.Len()) |
| 41 | + kv.value = value |
| 42 | + } else { |
| 43 | + ele := c.ll.PushFront(&entry{key, value}) |
| 44 | + c.cache[key] = ele |
| 45 | + c.nbytes += int64(len(key)) + int64(value.Len()) |
| 46 | + } |
| 47 | + for c.maxBytes != 0 && c.maxBytes < c.nbytes { |
| 48 | + c.RemoveOldest() |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | +// Get look ups a key's value |
| 53 | +func (c *Cache) Get(key string) (value Value, ok bool) { |
| 54 | + if ele, ok := c.cache[key]; ok { |
| 55 | + c.ll.MoveToFront(ele) |
| 56 | + kv := ele.Value.(*entry) |
| 57 | + return kv.value, true |
| 58 | + } |
| 59 | + return |
| 60 | +} |
| 61 | + |
| 62 | +// RemoveOldest removes the oldest item |
| 63 | +func (c *Cache) RemoveOldest() { |
| 64 | + ele := c.ll.Back() |
| 65 | + if ele != nil { |
| 66 | + c.ll.Remove(ele) |
| 67 | + kv := ele.Value.(*entry) |
| 68 | + delete(c.cache, kv.key) |
| 69 | + c.nbytes -= int64(len(kv.key)) + int64(kv.value.Len()) |
| 70 | + if c.OnEvicted != nil { |
| 71 | + c.OnEvicted(kv.key, kv.value) |
| 72 | + } |
| 73 | + } |
| 74 | +} |
| 75 | + |
| 76 | +// Len the number of cache entries |
| 77 | +func (c *Cache) Len() int { |
| 78 | + return c.ll.Len() |
| 79 | +} |
0 commit comments