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
|
|
}
|