mirror of
				https://github.com/duke-git/lancet.git
				synced 2025-10-31 10:46:24 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			122 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package algorithm
 | |
| 
 | |
| type lruNode[K comparable, V any] struct {
 | |
| 	key   K
 | |
| 	value V
 | |
| 	pre   *lruNode[K, V]
 | |
| 	next  *lruNode[K, V]
 | |
| }
 | |
| 
 | |
| // newLruNode return a lruNode pointer
 | |
| func newLruNode[K comparable, V any](key K, value V) *lruNode[K, V] {
 | |
| 	return &lruNode[K, V]{
 | |
| 		key:   key,
 | |
| 		value: value,
 | |
| 		pre:   nil,
 | |
| 		next:  nil,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // LRUCache lru cache (thread unsafe)
 | |
| type LRUCache[K comparable, V any] struct {
 | |
| 	cache    map[K]*lruNode[K, V]
 | |
| 	head     *lruNode[K, V]
 | |
| 	tail     *lruNode[K, V]
 | |
| 	capacity int
 | |
| 	length   int
 | |
| }
 | |
| 
 | |
| // NewLRUCache creates a LRUCache pointer instance.
 | |
| func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
 | |
| 	return &LRUCache[K, V]{
 | |
| 		cache:    make(map[K]*lruNode[K, V], capacity),
 | |
| 		head:     nil,
 | |
| 		tail:     nil,
 | |
| 		capacity: capacity,
 | |
| 		length:   0,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Get value of key from lru cache.
 | |
| // Play: https://go.dev/play/p/iUynEfOP8G0
 | |
| func (l *LRUCache[K, V]) Get(key K) (V, bool) {
 | |
| 	var value V
 | |
| 
 | |
| 	node, ok := l.cache[key]
 | |
| 	if ok {
 | |
| 		l.moveToTail(node)
 | |
| 		return node.value, true
 | |
| 	}
 | |
| 
 | |
| 	return value, false
 | |
| }
 | |
| 
 | |
| // Put value of key into lru cache.
 | |
| // Play: https://go.dev/play/p/iUynEfOP8G0
 | |
| func (l *LRUCache[K, V]) Put(key K, value V) {
 | |
| 	node, ok := l.cache[key]
 | |
| 	if !ok {
 | |
| 		newNode := newLruNode(key, value)
 | |
| 		l.cache[key] = newNode
 | |
| 		l.addNode(newNode)
 | |
| 
 | |
| 		if len(l.cache) > l.capacity {
 | |
| 			oldKey := l.deleteNode(l.head)
 | |
| 			delete(l.cache, oldKey)
 | |
| 		}
 | |
| 	} else {
 | |
| 		node.value = value
 | |
| 		l.moveToTail(node)
 | |
| 	}
 | |
| 	l.length = len(l.cache)
 | |
| }
 | |
| 
 | |
| // Delete item from lru cache.
 | |
| func (l *LRUCache[K, V]) Delete(key K) bool {
 | |
| 	node, ok := l.cache[key]
 | |
| 	if ok {
 | |
| 		key := l.deleteNode(node)
 | |
| 		delete(l.cache, key)
 | |
| 		return true
 | |
| 	}
 | |
| 	l.length = len(l.cache)
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // Len returns the number of items in the cache.
 | |
| func (l *LRUCache[K, V]) Len() int {
 | |
| 	return l.length
 | |
| }
 | |
| 
 | |
| func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) {
 | |
| 	if l.tail != nil {
 | |
| 		l.tail.next = node
 | |
| 		node.pre = l.tail
 | |
| 		node.next = nil
 | |
| 	}
 | |
| 	l.tail = node
 | |
| 	if l.head == nil {
 | |
| 		l.head = node
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (l *LRUCache[K, V]) deleteNode(node *lruNode[K, V]) K {
 | |
| 	if node == l.tail {
 | |
| 		l.tail = l.tail.pre
 | |
| 	} else if node == l.head {
 | |
| 		l.head = l.head.next
 | |
| 	} else {
 | |
| 		node.pre.next = node.next
 | |
| 		node.next.pre = node.pre
 | |
| 	}
 | |
| 	return node.key
 | |
| }
 | |
| 
 | |
| func (l *LRUCache[K, V]) moveToTail(node *lruNode[K, V]) {
 | |
| 	if l.tail == node {
 | |
| 		return
 | |
| 	}
 | |
| 	l.deleteNode(node)
 | |
| 	l.addNode(node)
 | |
| }
 | 
