github.com/avicd/go-utilx@v0.1.0/bufx/lru.go (about)

     1  package bufx
     2  
     3  import (
     4  	"github.com/avicd/go-utilx/datax"
     5  	"sync"
     6  )
     7  
     8  type LruCache[K comparable, V any] struct {
     9  	Size        int
    10  	store       map[K]*datax.LinkedNode[Entry[K, V]]
    11  	first       *datax.LinkedNode[Entry[K, V]]
    12  	last        *datax.LinkedNode[Entry[K, V]]
    13  	mutex       sync.RWMutex
    14  	firstLocker sync.Mutex
    15  }
    16  
    17  func (it *LruCache[K, V]) Get(key K) (V, bool) {
    18  	var ret V
    19  	var exist bool
    20  	it.mutex.RLock()
    21  	if node, ok := it.store[key]; ok {
    22  		it.asFirst(node)
    23  		ret = node.Item.Value
    24  		exist = true
    25  	}
    26  	it.mutex.RUnlock()
    27  	return ret, exist
    28  }
    29  
    30  func (it *LruCache[K, V]) asFirst(node *datax.LinkedNode[Entry[K, V]]) {
    31  	it.firstLocker.Lock()
    32  	if it.first != node {
    33  		if it.first == nil {
    34  			node.Remove()
    35  			it.first = node
    36  			it.last = node
    37  		} else {
    38  			if it.last == node {
    39  				it.last = node.Pre
    40  			}
    41  			node.Remove()
    42  			it.first.Insert(node)
    43  			it.first = node
    44  		}
    45  	}
    46  	it.firstLocker.Unlock()
    47  }
    48  
    49  func (it *LruCache[K, V]) removeLast() {
    50  	if it.last != nil {
    51  		delete(it.store, it.last.Item.Key)
    52  		if it.last.Pre != nil {
    53  			it.last = it.last.Pre
    54  			it.last.Next = nil
    55  		} else {
    56  			it.last = nil
    57  		}
    58  	}
    59  }
    60  
    61  func (it *LruCache[K, V]) Put(key K, val V) {
    62  	it.mutex.Lock()
    63  	node := it.store[key]
    64  	if node == nil {
    65  		if it.Size > 0 && len(it.store)+1 > it.Size {
    66  			it.removeLast()
    67  		}
    68  		node = &datax.LinkedNode[Entry[K, V]]{}
    69  	}
    70  	if it.store == nil {
    71  		it.store = map[K]*datax.LinkedNode[Entry[K, V]]{}
    72  	}
    73  	node.Item = Entry[K, V]{Key: key, Value: val}
    74  	it.store[key] = node
    75  	it.asFirst(node)
    76  	it.mutex.Unlock()
    77  }
    78  
    79  func (it *LruCache[K, V]) Remove(key K) bool {
    80  	it.mutex.Lock()
    81  	if node, ok := it.store[key]; ok {
    82  		delete(it.store, node.Item.Key)
    83  		if it.first == node {
    84  			it.first = node.Next
    85  		}
    86  		if it.last == node {
    87  			it.last = node.Pre
    88  		}
    89  		node.Remove()
    90  	}
    91  	it.mutex.Unlock()
    92  	return false
    93  }
    94  
    95  func (it *LruCache[K, V]) Len() int {
    96  	return len(it.store)
    97  }
    98  
    99  func (it *LruCache[K, V]) Clear() {
   100  	it.mutex.Lock()
   101  	it.store = map[K]*datax.LinkedNode[Entry[K, V]]{}
   102  	it.first = nil
   103  	it.last = nil
   104  	it.mutex.Unlock()
   105  }