Skip to content

Commit 9353717

Browse files
Add support for generics (#111)
1 parent bdf35e3 commit 9353717

12 files changed

+346
-191
lines changed

2q.go

+24-23
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"fmt"
55
"sync"
66

7-
"github.com/hashicorp/golang-lru/simplelru"
7+
"github.com/hashicorp/golang-lru/v2/simplelru"
88
)
99

1010
const (
@@ -26,25 +26,25 @@ const (
2626
// computationally about 2x the cost, and adds some metadata over
2727
// head. The ARCCache is similar, but does not require setting any
2828
// parameters.
29-
type TwoQueueCache struct {
29+
type TwoQueueCache[K comparable, V any] struct {
3030
size int
3131
recentSize int
3232

33-
recent simplelru.LRUCache
34-
frequent simplelru.LRUCache
35-
recentEvict simplelru.LRUCache
33+
recent simplelru.LRUCache[K, V]
34+
frequent simplelru.LRUCache[K, V]
35+
recentEvict simplelru.LRUCache[K, V]
3636
lock sync.RWMutex
3737
}
3838

3939
// New2Q creates a new TwoQueueCache using the default
4040
// values for the parameters.
41-
func New2Q(size int) (*TwoQueueCache, error) {
42-
return New2QParams(size, Default2QRecentRatio, Default2QGhostEntries)
41+
func New2Q[K comparable, V any](size int) (*TwoQueueCache[K, V], error) {
42+
return New2QParams[K, V](size, Default2QRecentRatio, Default2QGhostEntries)
4343
}
4444

4545
// New2QParams creates a new TwoQueueCache using the provided
4646
// parameter values.
47-
func New2QParams(size int, recentRatio, ghostRatio float64) (*TwoQueueCache, error) {
47+
func New2QParams[K comparable, V any](size int, recentRatio, ghostRatio float64) (*TwoQueueCache[K, V], error) {
4848
if size <= 0 {
4949
return nil, fmt.Errorf("invalid size")
5050
}
@@ -60,21 +60,21 @@ func New2QParams(size int, recentRatio, ghostRatio float64) (*TwoQueueCache, err
6060
evictSize := int(float64(size) * ghostRatio)
6161

6262
// Allocate the LRUs
63-
recent, err := simplelru.NewLRU(size, nil)
63+
recent, err := simplelru.NewLRU[K, V](size, nil)
6464
if err != nil {
6565
return nil, err
6666
}
67-
frequent, err := simplelru.NewLRU(size, nil)
67+
frequent, err := simplelru.NewLRU[K, V](size, nil)
6868
if err != nil {
6969
return nil, err
7070
}
71-
recentEvict, err := simplelru.NewLRU(evictSize, nil)
71+
recentEvict, err := simplelru.NewLRU[K, V](evictSize, nil)
7272
if err != nil {
7373
return nil, err
7474
}
7575

7676
// Initialize the cache
77-
c := &TwoQueueCache{
77+
c := &TwoQueueCache[K, V]{
7878
size: size,
7979
recentSize: recentSize,
8080
recent: recent,
@@ -85,7 +85,7 @@ func New2QParams(size int, recentRatio, ghostRatio float64) (*TwoQueueCache, err
8585
}
8686

8787
// Get looks up a key's value from the cache.
88-
func (c *TwoQueueCache) Get(key interface{}) (value interface{}, ok bool) {
88+
func (c *TwoQueueCache[K, V]) Get(key K) (value V, ok bool) {
8989
c.lock.Lock()
9090
defer c.lock.Unlock()
9191

@@ -103,11 +103,11 @@ func (c *TwoQueueCache) Get(key interface{}) (value interface{}, ok bool) {
103103
}
104104

105105
// No hit
106-
return nil, false
106+
return
107107
}
108108

109109
// Add adds a value to the cache.
110-
func (c *TwoQueueCache) Add(key, value interface{}) {
110+
func (c *TwoQueueCache[K, V]) Add(key K, value V) {
111111
c.lock.Lock()
112112
defer c.lock.Unlock()
113113

@@ -141,7 +141,7 @@ func (c *TwoQueueCache) Add(key, value interface{}) {
141141
}
142142

143143
// ensureSpace is used to ensure we have space in the cache
144-
func (c *TwoQueueCache) ensureSpace(recentEvict bool) {
144+
func (c *TwoQueueCache[K, V]) ensureSpace(recentEvict bool) {
145145
// If we have space, nothing to do
146146
recentLen := c.recent.Len()
147147
freqLen := c.frequent.Len()
@@ -153,7 +153,8 @@ func (c *TwoQueueCache) ensureSpace(recentEvict bool) {
153153
// the target, evict from there
154154
if recentLen > 0 && (recentLen > c.recentSize || (recentLen == c.recentSize && !recentEvict)) {
155155
k, _, _ := c.recent.RemoveOldest()
156-
c.recentEvict.Add(k, nil)
156+
var empty V
157+
c.recentEvict.Add(k, empty)
157158
return
158159
}
159160

@@ -162,15 +163,15 @@ func (c *TwoQueueCache) ensureSpace(recentEvict bool) {
162163
}
163164

164165
// Len returns the number of items in the cache.
165-
func (c *TwoQueueCache) Len() int {
166+
func (c *TwoQueueCache[K, V]) Len() int {
166167
c.lock.RLock()
167168
defer c.lock.RUnlock()
168169
return c.recent.Len() + c.frequent.Len()
169170
}
170171

171172
// Keys returns a slice of the keys in the cache.
172173
// The frequently used keys are first in the returned slice.
173-
func (c *TwoQueueCache) Keys() []interface{} {
174+
func (c *TwoQueueCache[K, V]) Keys() []K {
174175
c.lock.RLock()
175176
defer c.lock.RUnlock()
176177
k1 := c.frequent.Keys()
@@ -179,7 +180,7 @@ func (c *TwoQueueCache) Keys() []interface{} {
179180
}
180181

181182
// Remove removes the provided key from the cache.
182-
func (c *TwoQueueCache) Remove(key interface{}) {
183+
func (c *TwoQueueCache[K, V]) Remove(key K) {
183184
c.lock.Lock()
184185
defer c.lock.Unlock()
185186
if c.frequent.Remove(key) {
@@ -194,7 +195,7 @@ func (c *TwoQueueCache) Remove(key interface{}) {
194195
}
195196

196197
// Purge is used to completely clear the cache.
197-
func (c *TwoQueueCache) Purge() {
198+
func (c *TwoQueueCache[K, V]) Purge() {
198199
c.lock.Lock()
199200
defer c.lock.Unlock()
200201
c.recent.Purge()
@@ -204,15 +205,15 @@ func (c *TwoQueueCache) Purge() {
204205

205206
// Contains is used to check if the cache contains a key
206207
// without updating recency or frequency.
207-
func (c *TwoQueueCache) Contains(key interface{}) bool {
208+
func (c *TwoQueueCache[K, V]) Contains(key K) bool {
208209
c.lock.RLock()
209210
defer c.lock.RUnlock()
210211
return c.frequent.Contains(key) || c.recent.Contains(key)
211212
}
212213

213214
// Peek is used to inspect the cache value of a key
214215
// without updating recency or frequency.
215-
func (c *TwoQueueCache) Peek(key interface{}) (value interface{}, ok bool) {
216+
func (c *TwoQueueCache[K, V]) Peek(key K) (value V, ok bool) {
216217
c.lock.RLock()
217218
defer c.lock.RUnlock()
218219
if val, ok := c.frequent.Peek(key); ok {

2q_test.go

+9-9
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
)
66

77
func Benchmark2Q_Rand(b *testing.B) {
8-
l, err := New2Q(8192)
8+
l, err := New2Q[int64, int64](8192)
99
if err != nil {
1010
b.Fatalf("err: %v", err)
1111
}
@@ -34,7 +34,7 @@ func Benchmark2Q_Rand(b *testing.B) {
3434
}
3535

3636
func Benchmark2Q_Freq(b *testing.B) {
37-
l, err := New2Q(8192)
37+
l, err := New2Q[int64, int64](8192)
3838
if err != nil {
3939
b.Fatalf("err: %v", err)
4040
}
@@ -67,7 +67,7 @@ func Benchmark2Q_Freq(b *testing.B) {
6767

6868
func Test2Q_RandomOps(t *testing.T) {
6969
size := 128
70-
l, err := New2Q(128)
70+
l, err := New2Q[int64, int64](128)
7171
if err != nil {
7272
t.Fatalf("err: %v", err)
7373
}
@@ -93,7 +93,7 @@ func Test2Q_RandomOps(t *testing.T) {
9393
}
9494

9595
func Test2Q_Get_RecentToFrequent(t *testing.T) {
96-
l, err := New2Q(128)
96+
l, err := New2Q[int, int](128)
9797
if err != nil {
9898
t.Fatalf("err: %v", err)
9999
}
@@ -139,7 +139,7 @@ func Test2Q_Get_RecentToFrequent(t *testing.T) {
139139
}
140140

141141
func Test2Q_Add_RecentToFrequent(t *testing.T) {
142-
l, err := New2Q(128)
142+
l, err := New2Q[int, int](128)
143143
if err != nil {
144144
t.Fatalf("err: %v", err)
145145
}
@@ -173,7 +173,7 @@ func Test2Q_Add_RecentToFrequent(t *testing.T) {
173173
}
174174

175175
func Test2Q_Add_RecentEvict(t *testing.T) {
176-
l, err := New2Q(4)
176+
l, err := New2Q[int, int](4)
177177
if err != nil {
178178
t.Fatalf("err: %v", err)
179179
}
@@ -220,7 +220,7 @@ func Test2Q_Add_RecentEvict(t *testing.T) {
220220
}
221221

222222
func Test2Q(t *testing.T) {
223-
l, err := New2Q(128)
223+
l, err := New2Q[int, int](128)
224224
if err != nil {
225225
t.Fatalf("err: %v", err)
226226
}
@@ -268,7 +268,7 @@ func Test2Q(t *testing.T) {
268268

269269
// Test that Contains doesn't update recent-ness
270270
func Test2Q_Contains(t *testing.T) {
271-
l, err := New2Q(2)
271+
l, err := New2Q[int, int](2)
272272
if err != nil {
273273
t.Fatalf("err: %v", err)
274274
}
@@ -287,7 +287,7 @@ func Test2Q_Contains(t *testing.T) {
287287

288288
// Test that Peek doesn't update recent-ness
289289
func Test2Q_Peek(t *testing.T) {
290-
l, err := New2Q(2)
290+
l, err := New2Q[int, int](2)
291291
if err != nil {
292292
t.Fatalf("err: %v", err)
293293
}

0 commit comments

Comments
 (0)