diff options
author | 2022-11-11 12:18:38 +0100 | |
---|---|---|
committer | 2022-11-11 12:18:38 +0100 | |
commit | edcee14d07bae129e2d1a06d99c30fc6f659ff5e (patch) | |
tree | 5b9d605654347fe104c55bf4b0e7fb1e1533e2a0 /vendor/codeberg.org/gruf/go-maps/lru.go | |
parent | [feature] S3: add config flag to proxy S3 media (#1014) (diff) | |
download | gotosocial-edcee14d07bae129e2d1a06d99c30fc6f659ff5e.tar.xz |
[feature] Read + Write tombstones for deleted Actors (#1005)
* [feature] Read + Write tombstones for deleted Actors
* copyTombstone
* update to use resultcache instead of old ttl cache
Signed-off-by: kim <grufwub@gmail.com>
* update go-cache library to fix result cache capacity / ordering bugs
Signed-off-by: kim <grufwub@gmail.com>
* bump go-cache/v3 to v3.1.6 to fix bugs
Signed-off-by: kim <grufwub@gmail.com>
* switch on status code
* better explain ErrGone reasoning
Signed-off-by: kim <grufwub@gmail.com>
Co-authored-by: kim <grufwub@gmail.com>
Diffstat (limited to 'vendor/codeberg.org/gruf/go-maps/lru.go')
-rw-r--r-- | vendor/codeberg.org/gruf/go-maps/lru.go | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/vendor/codeberg.org/gruf/go-maps/lru.go b/vendor/codeberg.org/gruf/go-maps/lru.go new file mode 100644 index 000000000..06ea2ab10 --- /dev/null +++ b/vendor/codeberg.org/gruf/go-maps/lru.go @@ -0,0 +1,153 @@ +package maps + +import ( + "fmt" + "reflect" +) + +// LRU provides an ordered hashmap implementation that keeps elements ordered according to last recently used (hence, LRU). +type LRUMap[K comparable, V any] struct { + ordered[K, V] + size int +} + +// NewLRU returns a new instance of LRUMap with given initializing length and maximum capacity. +func NewLRU[K comparable, V any](len, cap int) *LRUMap[K, V] { + m := new(LRUMap[K, V]) + m.Init(len, cap) + return m +} + +// Init will initialize this map with initial length and maximum capacity. +func (m *LRUMap[K, V]) Init(len, cap int) { + if cap <= 0 { + panic("lru cap must be greater than zero") + } else if m.pool != nil { + panic("lru map already initialized") + } + m.ordered.hmap = make(map[K]*elem[K, V], len) + m.ordered.pool = allocElems[K, V](len) + m.size = cap +} + +// Get will fetch value for given key from map, in the process pushing it to the front of the map. Returns false if not found. +func (m *LRUMap[K, V]) Get(key K) (V, bool) { + if elem, ok := m.hmap[key]; ok { + // Ensure safe + m.write_check() + + // Unlink elem from list + m.list.Unlink(elem) + + // Push to front of list + m.list.PushFront(elem) + + return elem.V, true + } + var z V // zero value + return z, false +} + +// Add will add the given key-value pair to the map, pushing them to the front of the map. Returns false if already exists. Evicts old at maximum capacity. +func (m *LRUMap[K, V]) Add(key K, value V) bool { + return m.AddWithHook(key, value, nil) +} + +// AddWithHook performs .Add() but passing any evicted entry to given hook function. +func (m *LRUMap[K, V]) AddWithHook(key K, value V, evict func(K, V)) bool { + // Ensure safe + m.write_check() + + // Look for existing elem + elem, ok := m.hmap[key] + if ok { + return false + } + + if m.list.len >= m.size { + // We're at capacity, sir! + // Pop current tail elem + elem = m.list.PopTail() + + if evict != nil { + // Pass to evict hook + evict(elem.K, elem.V) + } + + // Delete key from map + delete(m.hmap, elem.K) + } else { + // Allocate elem + elem = m.alloc() + } + + // Set elem + elem.K = key + elem.V = value + + // Add element map entry + m.hmap[key] = elem + + // Push to front of list + m.list.PushFront(elem) + return true +} + +// Set will ensure that given key-value pair exists in the map, by either adding new or updating existing, pushing them to the front of the map. Evicts old at maximum capacity. +func (m *LRUMap[K, V]) Set(key K, value V) { + m.SetWithHook(key, value, nil) +} + +// SetWithHook performs .Set() but passing any evicted entry to given hook function. +func (m *LRUMap[K, V]) SetWithHook(key K, value V, evict func(K, V)) { + // Ensure safe + m.write_check() + + // Look for existing elem + elem, ok := m.hmap[key] + + if ok { + // Unlink elem from list + m.list.Unlink(elem) + + // Update existing + elem.V = value + } else { + if m.list.len >= m.size { + // We're at capacity, sir! + // Pop current tail elem + elem = m.list.PopTail() + + if evict != nil { + // Pass to evict hook + evict(elem.K, elem.V) + } + + // Delete key from map + delete(m.hmap, elem.K) + } else { + // Allocate elem + elem = m.alloc() + } + + // Set elem + elem.K = key + elem.V = value + + // Add element map entry + m.hmap[key] = elem + } + + // Push to front of list + m.list.PushFront(elem) +} + +// Cap returns the maximum capacity of this LRU map. +func (m *LRUMap[K, V]) Cap() int { + return m.size +} + +// Format implements fmt.Formatter, allowing performant string formatting of map. +func (m *LRUMap[K, V]) Format(state fmt.State, verb rune) { + m.format(reflect.TypeOf(m), state, verb) +} |