mirror of
https://github.com/sst/opencode.git
synced 2025-08-23 22:44:08 +00:00
125 lines
3.8 KiB
Go
125 lines
3.8 KiB
Go
// Package memoization implement a simple memoization cache. It's designed to
|
|
// improve performance in textarea.
|
|
package textarea
|
|
|
|
import (
|
|
"container/list"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
// Hasher is an interface that requires a Hash method. The Hash method is
|
|
// expected to return a string representation of the hash of the object.
|
|
type Hasher interface {
|
|
Hash() string
|
|
}
|
|
|
|
// entry is a struct that holds a key-value pair. It is used as an element
|
|
// in the evictionList of the MemoCache.
|
|
type entry[T any] struct {
|
|
key string
|
|
value T
|
|
}
|
|
|
|
// MemoCache is a struct that represents a cache with a set capacity. It
|
|
// uses an LRU (Least Recently Used) eviction policy. It is safe for
|
|
// concurrent use.
|
|
type MemoCache[H Hasher, T any] struct {
|
|
capacity int
|
|
mutex sync.Mutex
|
|
cache map[string]*list.Element // The cache holding the results
|
|
evictionList *list.List // A list to keep track of the order for LRU
|
|
hashableItems map[string]T // This map keeps track of the original hashable items (optional)
|
|
}
|
|
|
|
// NewMemoCache is a function that creates a new MemoCache with a given
|
|
// capacity. It returns a pointer to the created MemoCache.
|
|
func NewMemoCache[H Hasher, T any](capacity int) *MemoCache[H, T] {
|
|
return &MemoCache[H, T]{
|
|
capacity: capacity,
|
|
cache: make(map[string]*list.Element),
|
|
evictionList: list.New(),
|
|
hashableItems: make(map[string]T),
|
|
}
|
|
}
|
|
|
|
// Capacity is a method that returns the capacity of the MemoCache.
|
|
func (m *MemoCache[H, T]) Capacity() int {
|
|
return m.capacity
|
|
}
|
|
|
|
// Size is a method that returns the current size of the MemoCache. It is
|
|
// the number of items currently stored in the cache.
|
|
func (m *MemoCache[H, T]) Size() int {
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
return m.evictionList.Len()
|
|
}
|
|
|
|
// Get is a method that returns the value associated with the given
|
|
// hashable item in the MemoCache. If there is no corresponding value, the
|
|
// method returns nil.
|
|
func (m *MemoCache[H, T]) Get(h H) (T, bool) {
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
|
|
hashedKey := h.Hash()
|
|
if element, found := m.cache[hashedKey]; found {
|
|
m.evictionList.MoveToFront(element)
|
|
return element.Value.(*entry[T]).value, true
|
|
}
|
|
var result T
|
|
return result, false
|
|
}
|
|
|
|
// Set is a method that sets the value for the given hashable item in the
|
|
// MemoCache. If the cache is at capacity, it evicts the least recently
|
|
// used item before adding the new item.
|
|
func (m *MemoCache[H, T]) Set(h H, value T) {
|
|
m.mutex.Lock()
|
|
defer m.mutex.Unlock()
|
|
|
|
hashedKey := h.Hash()
|
|
if element, found := m.cache[hashedKey]; found {
|
|
m.evictionList.MoveToFront(element)
|
|
element.Value.(*entry[T]).value = value
|
|
return
|
|
}
|
|
|
|
// Check if the cache is at capacity
|
|
if m.evictionList.Len() >= m.capacity {
|
|
// Evict the least recently used item from the cache
|
|
toEvict := m.evictionList.Back()
|
|
if toEvict != nil {
|
|
evictedEntry := m.evictionList.Remove(toEvict).(*entry[T])
|
|
delete(m.cache, evictedEntry.key)
|
|
delete(m.hashableItems, evictedEntry.key) // if you're keeping track of original items
|
|
}
|
|
}
|
|
|
|
// Add the value to the cache and the evictionList
|
|
newEntry := &entry[T]{
|
|
key: hashedKey,
|
|
value: value,
|
|
}
|
|
element := m.evictionList.PushFront(newEntry)
|
|
m.cache[hashedKey] = element
|
|
m.hashableItems[hashedKey] = value // if you're keeping track of original items
|
|
}
|
|
|
|
// HString is a type that implements the Hasher interface for strings.
|
|
type HString string
|
|
|
|
// Hash is a method that returns the hash of the string.
|
|
func (h HString) Hash() string {
|
|
return fmt.Sprintf("%x", sha256.Sum256([]byte(h)))
|
|
}
|
|
|
|
// HInt is a type that implements the Hasher interface for integers.
|
|
type HInt int
|
|
|
|
// Hash is a method that returns the hash of the integer.
|
|
func (h HInt) Hash() string {
|
|
return fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprintf("%d", h))))
|
|
}
|