lru.go RawHistoryFolder

1// Package cache provides cache implementations for the application layer.
2package cache
3
4import (
5	"container/list"
6	"sync"
7)
8
9// LRU is a thread-safe LRU (Least Recently Used) cache with a fixed capacity.
10// It implements port.Cache[K, V].
11//
12// When the cache reaches capacity, the least recently accessed entry is evicted
13// to make room for new entries. Both Get and Set operations mark an entry as
14// recently used.
15type LRU[K comparable, V any] struct {
16	capacity int
17	mu       sync.RWMutex
18	items    map[K]*list.Element
19	order    *list.List // Front = most recent, Back = least recent
20}
21
22// entry holds a key-value pair in the LRU cache.
23type entry[K comparable, V any] struct {
24	key   K
25	value V
26}
27
28// NewLRU creates a new LRU cache with the given capacity.
29// Capacity must be positive; if zero or negative, a capacity of 1 is used.
30func NewLRU[K comparable, V any](capacity int) *LRU[K, V] {
31	if capacity <= 0 {
32		capacity = 1
33	}
34	return &LRU[K, V]{
35		capacity: capacity,
36		items:    make(map[K]*list.Element),
37		order:    list.New(),
38	}
39}
40
41// Get retrieves a value by key and marks it as recently used.
42// Returns the value and true if found, or the zero value and false if not found.
43func (c *LRU[K, V]) Get(key K) (V, bool) {
44	c.mu.Lock()
45	defer c.mu.Unlock()
46
47	if elem, ok := c.items[key]; ok {
48		c.order.MoveToFront(elem)
49		return elem.Value.(*entry[K, V]).value, true
50	}
51	var zero V
52	return zero, false
53}
54
55// Set adds or updates a value in the cache.
56// If the key already exists, its value is updated and it's marked as recently used.
57// If the cache is at capacity, the least recently used entry is evicted.
58func (c *LRU[K, V]) Set(key K, value V) {
59	c.mu.Lock()
60	defer c.mu.Unlock()
61
62	// Update existing entry
63	if elem, ok := c.items[key]; ok {
64		c.order.MoveToFront(elem)
65		elem.Value.(*entry[K, V]).value = value
66		return
67	}
68
69	// Evict LRU entry if at capacity
70	if c.order.Len() >= c.capacity {
71		oldest := c.order.Back()
72		if oldest != nil {
73			c.order.Remove(oldest)
74			delete(c.items, oldest.Value.(*entry[K, V]).key)
75		}
76	}
77
78	// Add new entry at front (most recent)
79	elem := c.order.PushFront(&entry[K, V]{key: key, value: value})
80	c.items[key] = elem
81}
82
83// Remove deletes a key from the cache.
84// If the key doesn't exist, this is a no-op.
85func (c *LRU[K, V]) Remove(key K) {
86	c.mu.Lock()
87	defer c.mu.Unlock()
88
89	if elem, ok := c.items[key]; ok {
90		c.order.Remove(elem)
91		delete(c.items, key)
92	}
93}
94
95// Len returns the number of items currently in the cache.
96func (c *LRU[K, V]) Len() int {
97	c.mu.RLock()
98	defer c.mu.RUnlock()
99	return c.order.Len()
100}
101
102// Clear removes all items from the cache.
103func (c *LRU[K, V]) Clear() {
104	c.mu.Lock()
105	defer c.mu.Unlock()
106
107	c.items = make(map[K]*list.Element)
108	c.order.Init()
109}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close