8 // EvictCallback is used to get a callback when a cache entry is evicted
9 type EvictCallback func(key interface{}, value interface{})
11 // LRU implements a non-thread safe fixed size LRU cache
15 items map[interface{}]*list.Element
19 // entry is used to hold a value in the evictList
25 // NewLRU constructs an LRU of the given size
26 func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
28 return nil, errors.New("Must provide a positive size")
32 evictList: list.New(),
33 items: make(map[interface{}]*list.Element),
39 // Purge is used to completely clear the cache.
40 func (c *LRU) Purge() {
41 for k, v := range c.items {
43 c.onEvict(k, v.Value.(*entry).value)
50 // Add adds a value to the cache. Returns true if an eviction occurred.
51 func (c *LRU) Add(key, value interface{}) (evicted bool) {
52 // Check for existing item
53 if ent, ok := c.items[key]; ok {
54 c.evictList.MoveToFront(ent)
55 ent.Value.(*entry).value = value
60 ent := &entry{key, value}
61 entry := c.evictList.PushFront(ent)
64 evict := c.evictList.Len() > c.size
65 // Verify size not exceeded
72 // Get looks up a key's value from the cache.
73 func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
74 if ent, ok := c.items[key]; ok {
75 c.evictList.MoveToFront(ent)
76 return ent.Value.(*entry).value, true
81 // Contains checks if a key is in the cache, without updating the recent-ness
82 // or deleting it for being stale.
83 func (c *LRU) Contains(key interface{}) (ok bool) {
88 // Peek returns the key value (or undefined if not found) without updating
89 // the "recently used"-ness of the key.
90 func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
92 if ent, ok = c.items[key]; ok {
93 return ent.Value.(*entry).value, true
98 // Remove removes the provided key from the cache, returning if the
100 func (c *LRU) Remove(key interface{}) (present bool) {
101 if ent, ok := c.items[key]; ok {
108 // RemoveOldest removes the oldest item from the cache.
109 func (c *LRU) RemoveOldest() (key interface{}, value interface{}, ok bool) {
110 ent := c.evictList.Back()
113 kv := ent.Value.(*entry)
114 return kv.key, kv.value, true
116 return nil, nil, false
119 // GetOldest returns the oldest entry
120 func (c *LRU) GetOldest() (key interface{}, value interface{}, ok bool) {
121 ent := c.evictList.Back()
123 kv := ent.Value.(*entry)
124 return kv.key, kv.value, true
126 return nil, nil, false
129 // Keys returns a slice of the keys in the cache, from oldest to newest.
130 func (c *LRU) Keys() []interface{} {
131 keys := make([]interface{}, len(c.items))
133 for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() {
134 keys[i] = ent.Value.(*entry).key
140 // Len returns the number of items in the cache.
141 func (c *LRU) Len() int {
142 return c.evictList.Len()
145 // removeOldest removes the oldest item from the cache.
146 func (c *LRU) removeOldest() {
147 ent := c.evictList.Back()
153 // removeElement is used to remove a given list element from the cache
154 func (c *LRU) removeElement(e *list.Element) {
155 c.evictList.Remove(e)
156 kv := e.Value.(*entry)
157 delete(c.items, kv.key)
158 if c.onEvict != nil {
159 c.onEvict(kv.key, kv.value)