Skip to content

Commit b1235e0

Browse files
committed
Add method GetAndAdd to LRU Cache
1 parent 80c9821 commit b1235e0

File tree

5 files changed

+68
-14
lines changed

5 files changed

+68
-14
lines changed

lru.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,23 @@ func (c *Cache) Purge() {
7171

7272
// Add adds a value to the cache. Returns true if an eviction occurred.
7373
func (c *Cache) Add(key, value interface{}) (evicted bool) {
74+
_, _, evicted = c.GetAndAdd(key, value)
75+
return
76+
}
77+
78+
// Get looks up a key's value from the cache.
79+
func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
80+
c.lock.Lock()
81+
value, ok = c.lru.Get(key)
82+
c.lock.Unlock()
83+
return value, ok
84+
}
85+
86+
// GetAndAdd returns the previous key's value from the cache and adds a new one.
87+
func (c *Cache) GetAndAdd(key, value interface{}) (previous interface{}, ok, evicted bool) {
7488
var k, v interface{}
7589
c.lock.Lock()
76-
evicted = c.lru.Add(key, value)
90+
previous, ok, evicted = c.lru.GetAndAdd(key, value)
7791
if c.onEvictedCB != nil && evicted {
7892
k, v = c.evictedKeys[0], c.evictedVals[0]
7993
c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
@@ -85,14 +99,6 @@ func (c *Cache) Add(key, value interface{}) (evicted bool) {
8599
return
86100
}
87101

88-
// Get looks up a key's value from the cache.
89-
func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
90-
c.lock.Lock()
91-
value, ok = c.lru.Get(key)
92-
c.lock.Unlock()
93-
return value, ok
94-
}
95-
96102
// Contains checks if a key is in the cache, without updating the
97103
// recent-ness or deleting it for being stale.
98104
func (c *Cache) Contains(key interface{}) bool {

lru_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,25 @@ func TestLRUAdd(t *testing.T) {
152152
}
153153
}
154154

155+
func TestLRU_GetAndAdd(t *testing.T) {
156+
l, err := New(1)
157+
if err != nil {
158+
t.Fatalf("err: %v", err)
159+
}
160+
if previous, ok, evicted := l.GetAndAdd(1, 1); ok || evicted {
161+
t.Errorf("1 should not be found, eviction should not be: %v, %v, %v", previous, ok, evicted)
162+
}
163+
if previous, ok, evicted := l.GetAndAdd(1, 10); !ok || previous != 1 || evicted {
164+
t.Errorf("1 should be returned as previous value, eviction should not be: %v, %v, %v", previous, ok, evicted)
165+
}
166+
if v, ok := l.Get(1); !ok || v != 10 {
167+
t.Errorf("1 should be set to 10: %v, %v", v, ok)
168+
}
169+
if previous, ok, evicted := l.GetAndAdd(2, 2); ok || !evicted {
170+
t.Errorf("2 should not be found, eviction should be: %v, %v, %v", previous, ok, evicted)
171+
}
172+
}
173+
155174
// test that Contains doesn't update recent-ness
156175
func TestLRUContains(t *testing.T) {
157176
l, err := New(2)

simplelru/lru.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,33 @@ func (c *LRU) Purge() {
4747
c.evictList.Init()
4848
}
4949

50-
// Add adds a value to the cache. Returns true if an eviction occurred.
50+
// Add adds a value to the cache. Returns true if an eviction occurred.
5151
func (c *LRU) Add(key, value interface{}) (evicted bool) {
52+
_, _, evicted = c.GetAndAdd(key, value)
53+
return
54+
}
55+
56+
// GetAndAdd returns the previous key's value from the cache and adds a new one.
57+
func (c *LRU) GetAndAdd(key, value interface{}) (previous interface{}, ok, evicted bool) {
5258
// Check for existing item
5359
if ent, ok := c.items[key]; ok {
5460
c.evictList.MoveToFront(ent)
61+
previous = ent.Value.(*entry).value
5562
ent.Value.(*entry).value = value
56-
return false
63+
return previous, true, false
5764
}
5865

5966
// Add new item
6067
ent := &entry{key, value}
6168
entry := c.evictList.PushFront(ent)
6269
c.items[key] = entry
6370

64-
evict := c.evictList.Len() > c.size
71+
evicted = c.evictList.Len() > c.size
6572
// Verify size not exceeded
66-
if evict {
73+
if evicted {
6774
c.removeOldest()
6875
}
69-
return evict
76+
return nil, false, evicted
7077
}
7178

7279
// Get looks up a key's value from the cache.

simplelru/lru_interface.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ type LRUCache interface {
1111
// updates the "recently used"-ness of the key. #value, isFound
1212
Get(key interface{}) (value interface{}, ok bool)
1313

14+
// Returns the previous key's value from the cache and adds a new one.
15+
GetAndAdd(key, value interface{}) (previous interface{}, ok, evicted bool)
16+
1417
// Checks if a key exists in cache without updating the recent-ness.
1518
Contains(key interface{}) (ok bool)
1619

simplelru/lru_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,25 @@ func TestLRU_Add(t *testing.T) {
128128
}
129129
}
130130

131+
func TestLRU_GetAndAdd(t *testing.T) {
132+
l, err := NewLRU(1, nil)
133+
if err != nil {
134+
t.Fatalf("err: %v", err)
135+
}
136+
if previous, ok, evicted := l.GetAndAdd(1, 1); ok || evicted {
137+
t.Errorf("1 should not be found, eviction should not be: %v, %v, %v", previous, ok, evicted)
138+
}
139+
if previous, ok, evicted := l.GetAndAdd(1, 10); !ok || previous != 1 || evicted {
140+
t.Errorf("1 should be returned as previous value, eviction should not be: %v, %v, %v", previous, ok, evicted)
141+
}
142+
if v, ok := l.Get(1); !ok || v != 10 {
143+
t.Errorf("1 should be set to 10: %v, %v", v, ok)
144+
}
145+
if previous, ok, evicted := l.GetAndAdd(2, 2); ok || !evicted {
146+
t.Errorf("2 should not be found, eviction should be: %v, %v, %v", previous, ok, evicted)
147+
}
148+
}
149+
131150
// Test that Contains doesn't update recent-ness
132151
func TestLRU_Contains(t *testing.T) {
133152
l, err := NewLRU(2, nil)

0 commit comments

Comments
 (0)