162 lines
4.4 KiB
Go
162 lines
4.4 KiB
Go
package cache
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/elliotchance/orderedmap/v2"
|
|
)
|
|
|
|
type RingMapInterface interface {
|
|
Exists(key string, value interface{}) bool
|
|
}
|
|
|
|
// Copied from https://github.com/prgsmall/ringmap to use orderedmap v2
|
|
|
|
type RingMap struct {
|
|
orderedMap *orderedmap.OrderedMap[string, interface{}]
|
|
capacity int
|
|
writeLock sync.RWMutex
|
|
}
|
|
|
|
func NewRingMap(capacity int) *RingMap {
|
|
return &RingMap{
|
|
orderedMap: orderedmap.NewOrderedMap[string, interface{}](),
|
|
capacity: capacity,
|
|
}
|
|
}
|
|
|
|
// Convenience function to check if key and value already exists
|
|
// If key and value does not exists, it is added
|
|
// If key exists with different value, it is replaced with new value
|
|
func (m *RingMap) Exists(key string, value interface{}) bool {
|
|
m.writeLock.RLock()
|
|
el := m.orderedMap.GetElement(key)
|
|
m.writeLock.RUnlock()
|
|
exists := el != nil
|
|
|
|
if exists && el.Value != value {
|
|
m.Delete(key)
|
|
exists = false
|
|
} else {
|
|
m.clearLast()
|
|
}
|
|
m.writeLock.Lock()
|
|
defer m.writeLock.Unlock()
|
|
m.orderedMap.Set(key, value)
|
|
|
|
return exists
|
|
}
|
|
|
|
// Get returns the value for a key. If the key does not exist, the second return
|
|
// parameter will be false and the value will be nil.
|
|
func (m *RingMap) Get(key string) (interface{}, bool) {
|
|
m.writeLock.RLock()
|
|
defer m.writeLock.RUnlock()
|
|
return m.orderedMap.Get(key)
|
|
}
|
|
|
|
// Set will set (or replace) a value for a key. If the key was new, then true
|
|
// will be returned. The returned value will be false if the value was replaced
|
|
// (even if the value was the same). If a new key is being added and the map is
|
|
// full, then the front element will be deleted to make room for the new element.
|
|
func (m *RingMap) Set(key string, value interface{}) bool {
|
|
_, didExist := m.Get(key)
|
|
|
|
if !didExist {
|
|
m.clearLast()
|
|
}
|
|
m.writeLock.Lock()
|
|
defer m.writeLock.Unlock()
|
|
m.orderedMap.Set(key, value)
|
|
|
|
return !didExist
|
|
}
|
|
|
|
// Put will set a value for a key. If the key already exists, it will be deleted
|
|
// from and a recreated at the end of the list. If the key was new, then true
|
|
// will be returned. The returned value will be false if the value was replaced
|
|
// (even if the value was the same). If a new key is being added and the map is
|
|
// full, then the front element will be deleted to make room for the new element.
|
|
func (m *RingMap) Put(key string, value interface{}) bool {
|
|
_, didExist := m.Get(key)
|
|
|
|
if didExist {
|
|
m.Delete(key)
|
|
} else {
|
|
m.clearLast()
|
|
}
|
|
m.writeLock.Lock()
|
|
defer m.writeLock.Unlock()
|
|
m.orderedMap.Set(key, value)
|
|
|
|
return !didExist
|
|
}
|
|
|
|
// GetOrDefault returns the value for a key. If the key does not exist, returns
|
|
// the default value instead.
|
|
func (m *RingMap) GetOrDefault(key string, defaultValue interface{}) interface{} {
|
|
m.writeLock.RLock()
|
|
defer m.writeLock.RUnlock()
|
|
return m.orderedMap.GetOrDefault(key, defaultValue)
|
|
}
|
|
|
|
// Len returns the number of elements in the map.
|
|
func (m *RingMap) Len() int {
|
|
m.writeLock.RLock()
|
|
defer m.writeLock.RUnlock()
|
|
return m.orderedMap.Len()
|
|
}
|
|
|
|
// Capacity returns the capacity of the map
|
|
func (m *RingMap) Capacity() int {
|
|
m.writeLock.RLock()
|
|
defer m.writeLock.RUnlock()
|
|
return m.capacity
|
|
}
|
|
|
|
// IsFull returns true if the number of elements in the map is Capacity()
|
|
func (m *RingMap) IsFull() bool {
|
|
m.writeLock.RLock()
|
|
defer m.writeLock.RUnlock()
|
|
return m.orderedMap.Len() == m.capacity
|
|
}
|
|
|
|
// Keys returns all of the keys in the order they were inserted. If a key was
|
|
// replaced it will retain the same position. To ensure most recently set keys
|
|
// are always at the end you must always Delete before Set.
|
|
func (m *RingMap) Keys() (keys []string) {
|
|
m.writeLock.RLock()
|
|
defer m.writeLock.RUnlock()
|
|
return m.orderedMap.Keys()
|
|
}
|
|
|
|
// Delete will remove a key from the map. It will return true if the key was
|
|
// removed (the key did exist).
|
|
func (m *RingMap) Delete(key string) (didDelete bool) {
|
|
m.writeLock.Lock()
|
|
defer m.writeLock.Unlock()
|
|
return m.orderedMap.Delete(key)
|
|
}
|
|
|
|
// Front will return the element that is the first (oldest Set element). If
|
|
// there are no elements this will return nil.
|
|
func (m *RingMap) Front() *orderedmap.Element[string, interface{}] {
|
|
m.writeLock.RLock()
|
|
defer m.writeLock.RUnlock()
|
|
return m.orderedMap.Front()
|
|
}
|
|
|
|
// Back will return the element that is the last (most recent Set element). If
|
|
// there are no elements this will return nil.
|
|
func (m *RingMap) Back() *orderedmap.Element[string, interface{}] {
|
|
m.writeLock.RLock()
|
|
defer m.writeLock.RUnlock()
|
|
return m.orderedMap.Back()
|
|
}
|
|
|
|
func (m *RingMap) clearLast() {
|
|
if m.IsFull() {
|
|
m.Delete(m.Front().Key)
|
|
}
|
|
}
|