109 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
		
		
			
		
	
	
			109 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Go
		
	
	
	
|  | package fifo | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"container/list" | ||
|  | ) | ||
|  | 
 | ||
|  | // Cache is used a FIFO (First in first out) cache replacement policy.
 | ||
|  | //
 | ||
|  | // In FIFO the item that enter the cache first is evicted first
 | ||
|  | // w/o any regard of how often or how many times it was accessed before.
 | ||
|  | type Cache[K comparable, V any] struct { | ||
|  | 	items    map[K]*list.Element | ||
|  | 	queue    *list.List // keys
 | ||
|  | 	capacity int | ||
|  | } | ||
|  | 
 | ||
|  | type entry[K comparable, V any] struct { | ||
|  | 	key K | ||
|  | 	val V | ||
|  | } | ||
|  | 
 | ||
|  | // Option is an option for FIFO cache.
 | ||
|  | type Option func(*options) | ||
|  | 
 | ||
|  | type options struct { | ||
|  | 	capacity int | ||
|  | } | ||
|  | 
 | ||
|  | func newOptions() *options { | ||
|  | 	return &options{ | ||
|  | 		capacity: 128, | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // WithCapacity is an option to set cache capacity.
 | ||
|  | func WithCapacity(cap int) Option { | ||
|  | 	return func(o *options) { | ||
|  | 		o.capacity = cap | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // NewCache creates a new non-thread safe FIFO cache whose capacity is the default size (128).
 | ||
|  | func NewCache[K comparable, V any](opts ...Option) *Cache[K, V] { | ||
|  | 	o := newOptions() | ||
|  | 	for _, optFunc := range opts { | ||
|  | 		optFunc(o) | ||
|  | 	} | ||
|  | 	return &Cache[K, V]{ | ||
|  | 		items:    make(map[K]*list.Element, o.capacity), | ||
|  | 		queue:    list.New(), | ||
|  | 		capacity: o.capacity, | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | // Set sets any item to the cache. replacing any existing item.
 | ||
|  | func (c *Cache[K, V]) Set(key K, val V) { | ||
|  | 	if c.queue.Len() == c.capacity { | ||
|  | 		e := c.dequeue() | ||
|  | 		delete(c.items, e.Value.(*entry[K, V]).key) | ||
|  | 	} | ||
|  | 	c.Delete(key) // delete old key if already exists specified key.
 | ||
|  | 	entry := &entry[K, V]{ | ||
|  | 		key: key, | ||
|  | 		val: val, | ||
|  | 	} | ||
|  | 	e := c.queue.PushBack(entry) | ||
|  | 	c.items[key] = e | ||
|  | } | ||
|  | 
 | ||
|  | // Get gets an item from the cache.
 | ||
|  | // Returns the item or zero value, and a bool indicating whether the key was found.
 | ||
|  | func (c *Cache[K, V]) Get(k K) (val V, ok bool) { | ||
|  | 	got, found := c.items[k] | ||
|  | 	if !found { | ||
|  | 		return | ||
|  | 	} | ||
|  | 	return got.Value.(*entry[K, V]).val, true | ||
|  | } | ||
|  | 
 | ||
|  | // Keys returns cache keys.
 | ||
|  | func (c *Cache[K, V]) Keys() []K { | ||
|  | 	keys := make([]K, 0, len(c.items)) | ||
|  | 	for e := c.queue.Front(); e != nil; e = e.Next() { | ||
|  | 		keys = append(keys, e.Value.(*entry[K, V]).key) | ||
|  | 	} | ||
|  | 	return keys | ||
|  | } | ||
|  | 
 | ||
|  | // Delete deletes the item with provided key from the cache.
 | ||
|  | func (c *Cache[K, V]) Delete(key K) (v V, found bool) { | ||
|  | 	if e, ok := c.items[key]; ok { | ||
|  | 		c.queue.Remove(e) | ||
|  | 		delete(c.items, key) | ||
|  | 		return e.Value.(*entry[K, V]).val, true | ||
|  | 	} | ||
|  | 	return | ||
|  | } | ||
|  | 
 | ||
|  | // Len returns the number of items in the cache.
 | ||
|  | func (c *Cache[K, V]) Len() int { | ||
|  | 	return c.queue.Len() | ||
|  | } | ||
|  | 
 | ||
|  | func (c *Cache[K, V]) dequeue() *list.Element { | ||
|  | 	e := c.queue.Front() | ||
|  | 	c.queue.Remove(e) | ||
|  | 	return e | ||
|  | } |