mirror of
				https://github.com/ehang-io/nps
				synced 2025-10-30 13:19:46 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			103 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package cache
 | |
| 
 | |
| import (
 | |
| 	"container/list"
 | |
| 	"sync"
 | |
| )
 | |
| 
 | |
| // Cache is an LRU cache. It is 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
 | |
| 
 | |
| 	//Execute this callback function when an element is culled
 | |
| 	OnEvicted func(key Key, value interface{})
 | |
| 
 | |
| 	ll    *list.List //list
 | |
| 	cache sync.Map
 | |
| }
 | |
| 
 | |
| // 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 0, the cache has no length limit.
 | |
| // 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),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // If the key value already exists, move the key to the front
 | |
| func (c *Cache) Add(key Key, value interface{}) {
 | |
| 	if ee, ok := c.cache.Load(key); ok {
 | |
| 		c.ll.MoveToFront(ee.(*list.Element)) // move to the front
 | |
| 		ee.(*list.Element).Value.(*entry).value = value
 | |
| 		return
 | |
| 	}
 | |
| 	ele := c.ll.PushFront(&entry{key, value})
 | |
| 	c.cache.Store(key, ele)
 | |
| 	if c.MaxEntries != 0 && c.ll.Len() > c.MaxEntries { // Remove the oldest element if the limit is exceeded
 | |
| 		c.RemoveOldest()
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Get looks up a key's value from the cache.
 | |
| func (c *Cache) Get(key Key) (value interface{}, ok bool) {
 | |
| 	if ele, hit := c.cache.Load(key); hit {
 | |
| 		c.ll.MoveToFront(ele.(*list.Element))
 | |
| 		return ele.(*list.Element).Value.(*entry).value, true
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| // Remove removes the provided key from the cache.
 | |
| func (c *Cache) Remove(key Key) {
 | |
| 	if ele, hit := c.cache.Load(key); hit {
 | |
| 		c.removeElement(ele.(*list.Element))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // RemoveOldest removes the oldest item from the cache.
 | |
| func (c *Cache) RemoveOldest() {
 | |
| 	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)
 | |
| 	c.cache.Delete(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 {
 | |
| 	return c.ll.Len()
 | |
| }
 | |
| 
 | |
| // Clear purges all stored items from the cache.
 | |
| func (c *Cache) Clear() {
 | |
| 	if c.OnEvicted != nil {
 | |
| 		c.cache.Range(func(key, value interface{}) bool {
 | |
| 			kv := value.(*list.Element).Value.(*entry)
 | |
| 			c.OnEvicted(kv.key, kv.value)
 | |
| 			return true
 | |
| 		})
 | |
| 	}
 | |
| 	c.ll = nil
 | |
| }
 | 
