github.com/theQRL/go-zond@v0.1.1/common/lru/basiclru.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package lru implements generically-typed LRU caches.
    18  package lru
    19  
    20  // BasicLRU is a simple LRU cache.
    21  //
    22  // This type is not safe for concurrent use.
    23  // The zero value is not valid, instances must be created using NewCache.
    24  type BasicLRU[K comparable, V any] struct {
    25  	list  *list[K]
    26  	items map[K]cacheItem[K, V]
    27  	cap   int
    28  }
    29  
    30  type cacheItem[K any, V any] struct {
    31  	elem  *listElem[K]
    32  	value V
    33  }
    34  
    35  // NewBasicLRU creates a new LRU cache.
    36  func NewBasicLRU[K comparable, V any](capacity int) BasicLRU[K, V] {
    37  	if capacity <= 0 {
    38  		capacity = 1
    39  	}
    40  	c := BasicLRU[K, V]{
    41  		items: make(map[K]cacheItem[K, V]),
    42  		list:  newList[K](),
    43  		cap:   capacity,
    44  	}
    45  	return c
    46  }
    47  
    48  // Add adds a value to the cache. Returns true if an item was evicted to store the new item.
    49  func (c *BasicLRU[K, V]) Add(key K, value V) (evicted bool) {
    50  	item, ok := c.items[key]
    51  	if ok {
    52  		// Already exists in cache.
    53  		item.value = value
    54  		c.items[key] = item
    55  		c.list.moveToFront(item.elem)
    56  		return false
    57  	}
    58  
    59  	var elem *listElem[K]
    60  	if c.Len() >= c.cap {
    61  		elem = c.list.removeLast()
    62  		delete(c.items, elem.v)
    63  		evicted = true
    64  	} else {
    65  		elem = new(listElem[K])
    66  	}
    67  
    68  	// Store the new item.
    69  	// Note that, if another item was evicted, we re-use its list element here.
    70  	elem.v = key
    71  	c.items[key] = cacheItem[K, V]{elem, value}
    72  	c.list.pushElem(elem)
    73  	return evicted
    74  }
    75  
    76  // Contains reports whether the given key exists in the cache.
    77  func (c *BasicLRU[K, V]) Contains(key K) bool {
    78  	_, ok := c.items[key]
    79  	return ok
    80  }
    81  
    82  // Get retrieves a value from the cache. This marks the key as recently used.
    83  func (c *BasicLRU[K, V]) Get(key K) (value V, ok bool) {
    84  	item, ok := c.items[key]
    85  	if !ok {
    86  		return value, false
    87  	}
    88  	c.list.moveToFront(item.elem)
    89  	return item.value, true
    90  }
    91  
    92  // GetOldest retrieves the least-recently-used item.
    93  // Note that this does not update the item's recency.
    94  func (c *BasicLRU[K, V]) GetOldest() (key K, value V, ok bool) {
    95  	lastElem := c.list.last()
    96  	if lastElem == nil {
    97  		return key, value, false
    98  	}
    99  	key = lastElem.v
   100  	item := c.items[key]
   101  	return key, item.value, true
   102  }
   103  
   104  // Len returns the current number of items in the cache.
   105  func (c *BasicLRU[K, V]) Len() int {
   106  	return len(c.items)
   107  }
   108  
   109  // Peek retrieves a value from the cache, but does not mark the key as recently used.
   110  func (c *BasicLRU[K, V]) Peek(key K) (value V, ok bool) {
   111  	item, ok := c.items[key]
   112  	return item.value, ok
   113  }
   114  
   115  // Purge empties the cache.
   116  func (c *BasicLRU[K, V]) Purge() {
   117  	c.list.init()
   118  	for k := range c.items {
   119  		delete(c.items, k)
   120  	}
   121  }
   122  
   123  // Remove drops an item from the cache. Returns true if the key was present in cache.
   124  func (c *BasicLRU[K, V]) Remove(key K) bool {
   125  	item, ok := c.items[key]
   126  	if ok {
   127  		delete(c.items, key)
   128  		c.list.remove(item.elem)
   129  	}
   130  	return ok
   131  }
   132  
   133  // RemoveOldest drops the least recently used item.
   134  func (c *BasicLRU[K, V]) RemoveOldest() (key K, value V, ok bool) {
   135  	lastElem := c.list.last()
   136  	if lastElem == nil {
   137  		return key, value, false
   138  	}
   139  
   140  	key = lastElem.v
   141  	item := c.items[key]
   142  	delete(c.items, key)
   143  	c.list.remove(lastElem)
   144  	return key, item.value, true
   145  }
   146  
   147  // Keys returns all keys in the cache.
   148  func (c *BasicLRU[K, V]) Keys() []K {
   149  	keys := make([]K, 0, len(c.items))
   150  	return c.list.appendTo(keys)
   151  }
   152  
   153  // list is a doubly-linked list holding items of type he.
   154  // The zero value is not valid, use newList to create lists.
   155  type list[T any] struct {
   156  	root listElem[T]
   157  }
   158  
   159  type listElem[T any] struct {
   160  	next *listElem[T]
   161  	prev *listElem[T]
   162  	v    T
   163  }
   164  
   165  func newList[T any]() *list[T] {
   166  	l := new(list[T])
   167  	l.init()
   168  	return l
   169  }
   170  
   171  // init reinitializes the list, making it empty.
   172  func (l *list[T]) init() {
   173  	l.root.next = &l.root
   174  	l.root.prev = &l.root
   175  }
   176  
   177  // push adds an element to the front of the list.
   178  func (l *list[T]) pushElem(e *listElem[T]) {
   179  	e.prev = &l.root
   180  	e.next = l.root.next
   181  	l.root.next = e
   182  	e.next.prev = e
   183  }
   184  
   185  // moveToFront makes 'node' the head of the list.
   186  func (l *list[T]) moveToFront(e *listElem[T]) {
   187  	e.prev.next = e.next
   188  	e.next.prev = e.prev
   189  	l.pushElem(e)
   190  }
   191  
   192  // remove removes an element from the list.
   193  func (l *list[T]) remove(e *listElem[T]) {
   194  	e.prev.next = e.next
   195  	e.next.prev = e.prev
   196  	e.next, e.prev = nil, nil
   197  }
   198  
   199  // removeLast removes the last element of the list.
   200  func (l *list[T]) removeLast() *listElem[T] {
   201  	last := l.last()
   202  	if last != nil {
   203  		l.remove(last)
   204  	}
   205  	return last
   206  }
   207  
   208  // last returns the last element of the list, or nil if the list is empty.
   209  func (l *list[T]) last() *listElem[T] {
   210  	e := l.root.prev
   211  	if e == &l.root {
   212  		return nil
   213  	}
   214  	return e
   215  }
   216  
   217  // appendTo appends all list elements to a slice.
   218  func (l *list[T]) appendTo(slice []T) []T {
   219  	for e := l.root.prev; e != &l.root; e = e.prev {
   220  		slice = append(slice, e.v)
   221  	}
   222  	return slice
   223  }