forked from toolshed/abra
		
	
		
			
				
	
	
		
			134 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2013 Google Inc.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|      http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| // Package lru implements an LRU cache.
 | |
| package lru
 | |
| 
 | |
| import "container/list"
 | |
| 
 | |
| // Cache is an LRU cache. It is not safe for concurrent access.
 | |
| type Cache struct {
 | |
| 	// MaxEntries is the maximum number of cache entries before
 | |
| 	// an item is evicted. Zero means no limit.
 | |
| 	MaxEntries int
 | |
| 
 | |
| 	// OnEvicted optionally specifies a callback function to be
 | |
| 	// executed when an entry is purged from the cache.
 | |
| 	OnEvicted func(key Key, value interface{})
 | |
| 
 | |
| 	ll    *list.List
 | |
| 	cache map[interface{}]*list.Element
 | |
| }
 | |
| 
 | |
| // A Key may be any value that is comparable. See http://golang.org/ref/spec#Comparison_operators
 | |
| type Key interface{}
 | |
| 
 | |
| type entry struct {
 | |
| 	key   Key
 | |
| 	value interface{}
 | |
| }
 | |
| 
 | |
| // New creates a new Cache.
 | |
| // If maxEntries is zero, the cache has no limit and it's assumed
 | |
| // that eviction is done by the caller.
 | |
| func New(maxEntries int) *Cache {
 | |
| 	return &Cache{
 | |
| 		MaxEntries: maxEntries,
 | |
| 		ll:         list.New(),
 | |
| 		cache:      make(map[interface{}]*list.Element),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Add adds a value to the cache.
 | |
| func (c *Cache) Add(key Key, value interface{}) {
 | |
| 	if c.cache == nil {
 | |
| 		c.cache = make(map[interface{}]*list.Element)
 | |
| 		c.ll = list.New()
 | |
| 	}
 | |
| 	if ee, ok := c.cache[key]; ok {
 | |
| 		c.ll.MoveToFront(ee)
 | |
| 		ee.Value.(*entry).value = value
 | |
| 		return
 | |
| 	}
 | |
| 	ele := c.ll.PushFront(&entry{key, value})
 | |
| 	c.cache[key] = ele
 | |
| 	if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries {
 | |
| 		c.RemoveOldest()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Get looks up a key's value from the cache.
 | |
| func (c *Cache) Get(key Key) (value interface{}, ok bool) {
 | |
| 	if c.cache == nil {
 | |
| 		return
 | |
| 	}
 | |
| 	if ele, hit := c.cache[key]; hit {
 | |
| 		c.ll.MoveToFront(ele)
 | |
| 		return ele.Value.(*entry).value, true
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Remove removes the provided key from the cache.
 | |
| func (c *Cache) Remove(key Key) {
 | |
| 	if c.cache == nil {
 | |
| 		return
 | |
| 	}
 | |
| 	if ele, hit := c.cache[key]; hit {
 | |
| 		c.removeElement(ele)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // RemoveOldest removes the oldest item from the cache.
 | |
| func (c *Cache) RemoveOldest() {
 | |
| 	if c.cache == nil {
 | |
| 		return
 | |
| 	}
 | |
| 	ele := c.ll.Back()
 | |
| 	if ele != nil {
 | |
| 		c.removeElement(ele)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (c *Cache) removeElement(e *list.Element) {
 | |
| 	c.ll.Remove(e)
 | |
| 	kv := e.Value.(*entry)
 | |
| 	delete(c.cache, kv.key)
 | |
| 	if c.OnEvicted != nil {
 | |
| 		c.OnEvicted(kv.key, kv.value)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Len returns the number of items in the cache.
 | |
| func (c *Cache) Len() int {
 | |
| 	if c.cache == nil {
 | |
| 		return 0
 | |
| 	}
 | |
| 	return c.ll.Len()
 | |
| }
 | |
| 
 | |
| // Clear purges all stored items from the cache.
 | |
| func (c *Cache) Clear() {
 | |
| 	if c.OnEvicted != nil {
 | |
| 		for _, e := range c.cache {
 | |
| 			kv := e.Value.(*entry)
 | |
| 			c.OnEvicted(kv.key, kv.value)
 | |
| 		}
 | |
| 	}
 | |
| 	c.ll = nil
 | |
| 	c.cache = nil
 | |
| }
 |