Skip to content

Commit e8cdb07

Browse files
sanad haj yahyashaj13
sanad haj yahya
authored andcommitted
feat: add cache front/back method to get the first/last element
1 parent 32ad35b commit e8cdb07

File tree

15 files changed

+170
-9
lines changed

15 files changed

+170
-9
lines changed

arc/arc.go

+14
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ type arc struct {
3232
b2 *internal.Cache
3333
}
3434

35+
func (a *arc) Front() interface{} {
36+
if k := a.t1.Front(); k != nil {
37+
return k
38+
}
39+
return a.t2.Front()
40+
}
41+
42+
func (a *arc) Back() interface{} {
43+
if k := a.t1.Back(); k != nil {
44+
return k
45+
}
46+
return a.t2.Back()
47+
}
48+
3549
func (a *arc) Load(key interface{}) (value interface{}, ok bool) {
3650
if val, ok := a.t1.Peek(key); ok {
3751
exp, _ := a.t1.Expiry(key)

arc/arc_test.go

+3
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,11 @@ func TestARCc(t *testing.T) {
5353

5454
a.Store(1, 1)
5555
a.Load(1)
56+
5657
assert.Equal(t, 0, a.t1.Len())
5758
assert.Equal(t, 1, a.t2.Len())
59+
assert.Equal(t, 1, a.Front())
60+
assert.Equal(t, 1, a.Back())
5861

5962
a.Delete(1)
6063
}

cache.go

+29-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@ type Event = internal.Event
2424

2525
// Cache stores data so that future requests for that data can be served faster.
2626
type Cache interface {
27+
// Front returns the first key of cache or nil if the cache is empty.
28+
//
29+
// # Experimental
30+
//
31+
// Notice: This func is EXPERIMENTAL and may be changed or removed in a
32+
// later release.
33+
Front() interface{}
34+
// Back returns the last key of cache or nil if the cache is empty.
35+
//
36+
// # Experimental
37+
//
38+
// Notice: This func is EXPERIMENTAL and may be changed or removed in a
39+
// later release.
40+
Back() interface{}
2741
// Load returns key value.
2842
Load(key interface{}) (interface{}, bool)
2943
// Peek returns key value without updating the underlying "recent-ness".
@@ -91,7 +105,7 @@ type Cache interface {
91105
// GC is a long running function, it returns when ctx done, therefore the
92106
// caller must start it in its own goroutine.
93107
//
94-
// Experimental
108+
// # Experimental
95109
//
96110
// Notice: This func is EXPERIMENTAL and may be changed or removed in a
97111
// later release.
@@ -142,6 +156,20 @@ type cache struct {
142156
unsafe Cache
143157
}
144158

159+
func (c *cache) Front() interface{} {
160+
c.mu.Lock()
161+
k := c.unsafe.Front()
162+
c.mu.Unlock()
163+
return k
164+
}
165+
166+
func (c *cache) Back() interface{} {
167+
c.mu.Lock()
168+
k := c.unsafe.Back()
169+
c.mu.Unlock()
170+
return k
171+
}
172+
145173
func (c *cache) Load(key interface{}) (interface{}, bool) {
146174
c.mu.Lock()
147175
v, ok := c.unsafe.Load(key)

fifo/fifo.go

+14
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ func (c *collection) Discard() (e *internal.Entry) {
4242
return
4343
}
4444

45+
func (c *collection) Front() (e *internal.Entry) {
46+
if le := c.ll.Front(); le != nil {
47+
e = le.Value.(*internal.Entry)
48+
}
49+
return
50+
}
51+
52+
func (c *collection) Back() (e *internal.Entry) {
53+
if le := c.ll.Back(); le != nil {
54+
e = le.Value.(*internal.Entry)
55+
}
56+
return
57+
}
58+
4559
func (c *collection) Len() int {
4660
return c.ll.Len()
4761
}

fifo/fifo_test.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ func TestCollection(t *testing.T) {
2828
}
2929
}
3030

31+
front := c.Front()
32+
back := c.Back()
3133
oldest := c.Discard()
3234
c.Remove(entries[2])
33-
back := c.ll.Back().Value.(*internal.Entry)
3435

36+
assert.Equal(t, 1, front.Key)
37+
assert.Equal(t, 3, back.Key)
3538
assert.Equal(t, 1, oldest.Key)
3639
assert.Equal(t, 1, c.Len())
37-
assert.Equal(t, 2, back.Key)
40+
assert.Equal(t, 2, c.Back().Key)
3841
}

idle/idle.go

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ func New(cap int) libcache.Cache {
1818

1919
type idle struct{}
2020

21+
func (idle) Front() (v interface{}) { return }
22+
func (idle) Back() (v interface{}) { return }
2123
func (idle) Load(interface{}) (v interface{}, ok bool) { return }
2224
func (idle) Peek(interface{}) (v interface{}, ok bool) { return }
2325
func (idle) Keys() (keys []interface{}) { return }

internal/cache.go

+26
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ type Collection interface {
5353
Add(*Entry)
5454
Remove(*Entry)
5555
Discard() *Entry
56+
Front() *Entry
57+
Back() *Entry
5658
Len() int
5759
Init()
5860
}
@@ -97,6 +99,30 @@ type Cache struct {
9799
capacity int
98100
}
99101

102+
// Front returns the first key of cache or nil if the cache is empty.
103+
func (c *Cache) Front() interface{} {
104+
// Run GC inline before get the front entry.
105+
c.GC()
106+
107+
if e := c.coll.Front(); e != nil {
108+
return e.Key
109+
}
110+
111+
return nil
112+
}
113+
114+
// Back returns the last key of cache or nil if the cache is empty.
115+
func (c *Cache) Back() interface{} {
116+
// Run GC inline before get the back entry.
117+
c.GC()
118+
119+
if e := c.coll.Back(); e != nil {
120+
return e.Key
121+
}
122+
123+
return nil
124+
}
125+
100126
// Load returns key value.
101127
func (c *Cache) Load(key interface{}) (interface{}, bool) {
102128
return c.get(key, false)

lfu/lfu.go

+14
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ func (f *collection) Discard() (e *internal.Entry) {
5757
return heap.Pop(f).(*element).value
5858
}
5959

60+
func (f *collection) Front() (e *internal.Entry) {
61+
if f.Len() > 0 {
62+
e = (*f)[f.Len()-1].value
63+
}
64+
return
65+
}
66+
67+
func (f *collection) Back() (e *internal.Entry) {
68+
if f.Len() > 0 {
69+
e = (*f)[0].value
70+
}
71+
return
72+
}
73+
6074
func (f *collection) Move(e *internal.Entry) {
6175
ele := e.Element.(*element)
6276
ele.count++

lfu/lfu_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,13 @@ func TestCollection(t *testing.T) {
2727
}
2828
}
2929

30+
front := f.Front()
31+
back := f.Back()
3032
oldest := f.Discard()
3133
f.Remove(entries[2])
3234

35+
assert.Equal(t, front.Key, 2)
36+
assert.Equal(t, back.Key, 1)
3337
assert.Equal(t, oldest.Key, 1)
3438
assert.Equal(t, f.Len(), 1)
3539
assert.Equal(t, (*f)[0].value.Key, 2)

lifo/lifo.go

+14
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ func (c *collection) Discard() (e *internal.Entry) {
4242
return
4343
}
4444

45+
func (c *collection) Front() (e *internal.Entry) {
46+
if le := c.ll.Front(); le != nil {
47+
e = le.Value.(*internal.Entry)
48+
}
49+
return
50+
}
51+
52+
func (c *collection) Back() (e *internal.Entry) {
53+
if le := c.ll.Back(); le != nil {
54+
e = le.Value.(*internal.Entry)
55+
}
56+
return
57+
}
58+
4559
func (c *collection) Len() int {
4660
return c.ll.Len()
4761
}

lifo/lifo_test.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,15 @@ func TestCollection(t *testing.T) {
2828
}
2929
}
3030

31+
front := c.Front()
32+
back := c.Back()
33+
3134
oldest := c.Discard()
3235
c.Remove(entries[0])
33-
back := c.ll.Back().Value.(*internal.Entry)
3436

37+
assert.Equal(t, 1, front.Key)
38+
assert.Equal(t, 3, back.Key)
3539
assert.Equal(t, 3, oldest.Key)
3640
assert.Equal(t, 1, c.Len())
37-
assert.Equal(t, 2, back.Key)
41+
assert.Equal(t, 2, c.Back().Key)
3842
}

lru/lru.go

+14
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ func (c *collection) Discard() (e *internal.Entry) {
4545
return
4646
}
4747

48+
func (c *collection) Front() (e *internal.Entry) {
49+
if le := c.ll.Front(); le != nil {
50+
e = le.Value.(*internal.Entry)
51+
}
52+
return
53+
}
54+
55+
func (c *collection) Back() (e *internal.Entry) {
56+
if le := c.ll.Back(); le != nil {
57+
e = le.Value.(*internal.Entry)
58+
}
59+
return
60+
}
61+
4862
func (c *collection) Len() int {
4963
return c.ll.Len()
5064
}

lru/lru_test.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,15 @@ func TestCollection(t *testing.T) {
2828
}
2929
}
3030

31+
front := c.Front()
32+
back := c.Back()
33+
3134
oldest := c.Discard()
3235
c.Remove(entries[2])
33-
back := c.ll.Back().Value.(*internal.Entry)
3436

37+
assert.Equal(t, 3, front.Key)
38+
assert.Equal(t, 1, back.Key)
3539
assert.Equal(t, 1, oldest.Key)
3640
assert.Equal(t, 1, c.Len())
37-
assert.Equal(t, 2, back.Key)
41+
assert.Equal(t, 2, c.Back().Key)
3842
}

mru/mru.go

+14
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ func (c *collection) Discard() (e *internal.Entry) {
4545
return
4646
}
4747

48+
func (c *collection) Front() (e *internal.Entry) {
49+
if le := c.ll.Front(); le != nil {
50+
e = le.Value.(*internal.Entry)
51+
}
52+
return
53+
}
54+
55+
func (c *collection) Back() (e *internal.Entry) {
56+
if le := c.ll.Back(); le != nil {
57+
e = le.Value.(*internal.Entry)
58+
}
59+
return
60+
}
61+
4862
func (c *collection) Len() int {
4963
return c.ll.Len()
5064
}

mru/mru_test.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ func TestCollection(t *testing.T) {
2828
}
2929
}
3030

31+
front := c.Front()
32+
back := c.Back()
3133
oldest := c.Discard()
3234
c.Remove(entries[1])
33-
back := c.ll.Back().Value.(*internal.Entry)
3435

36+
assert.Equal(t, 3, front.Key)
37+
assert.Equal(t, 1, back.Key)
3538
assert.Equal(t, 3, oldest.Key)
3639
assert.Equal(t, 1, c.Len())
37-
assert.Equal(t, 1, back.Key)
40+
assert.Equal(t, 1, c.Back().Key)
3841
}

0 commit comments

Comments
 (0)