mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 23:52:26 -06:00 
			
		
		
		
	* [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>
		
			
				
	
	
		
			153 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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)
 | 
						|
}
 |