Skip to content

Commit 63e7f6b

Browse files
committed
added WithReferenceCount option
1 parent 8c94293 commit 63e7f6b

File tree

6 files changed

+99
-9
lines changed

6 files changed

+99
-9
lines changed

cache.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ var (
3838

3939
// Item is an item
4040
type Item[K comparable, V any] struct {
41-
Key K
42-
Value V
43-
Expiration time.Time
41+
Key K
42+
Value V
43+
Expiration time.Time
44+
InitialReferenceCount int
4445
}
4546

4647
// Expired returns true if the item has expired.
@@ -51,13 +52,20 @@ func (item *Item[K, V]) Expired() bool {
5152
return nowFunc().After(item.Expiration)
5253
}
5354

55+
// GetReferenceCount returns reference count to be used when setting
56+
// the cache item for the first time.
57+
func (item *Item[K, V]) GetReferenceCount() int {
58+
return item.InitialReferenceCount
59+
}
60+
5461
var nowFunc = time.Now
5562

5663
// ItemOption is an option for cache item.
5764
type ItemOption func(*itemOptions)
5865

5966
type itemOptions struct {
60-
expiration time.Time // default none
67+
expiration time.Time // default none
68+
referenceCount int
6169
}
6270

6371
// WithExpiration is an option to set expiration time for any items.
@@ -68,16 +76,26 @@ func WithExpiration(exp time.Duration) ItemOption {
6876
}
6977
}
7078

79+
// WithReferenceCount is an option to set reference count for any items.
80+
// This option is only applicable to cache policies that have a reference count (e.g., Clock, LFU).
81+
// referenceCount specifies the reference count value to set for the cache item.
82+
func WithReferenceCount(referenceCount int) ItemOption {
83+
return func(o *itemOptions) {
84+
o.referenceCount = referenceCount
85+
}
86+
}
87+
7188
// newItem creates a new item with specified any options.
7289
func newItem[K comparable, V any](key K, val V, opts ...ItemOption) *Item[K, V] {
7390
o := new(itemOptions)
7491
for _, optFunc := range opts {
7592
optFunc(o)
7693
}
7794
return &Item[K, V]{
78-
Key: key,
79-
Value: val,
80-
Expiration: o.expiration,
95+
Key: key,
96+
Value: val,
97+
Expiration: o.expiration,
98+
InitialReferenceCount: o.referenceCount,
8199
}
82100
}
83101

example_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,24 @@ func ExampleWithExpiration() {
7676
// 0 false
7777
}
7878

79+
func ExampleWithReferenceCount() {
80+
c := cache.New(cache.AsLFU[string, int]())
81+
c.Set("a", 1, cache.WithReferenceCount(2))
82+
83+
// check item is set.
84+
gota, aok := c.Get("a")
85+
fmt.Println(gota, aok)
86+
87+
c.Set("b", 2, cache.WithReferenceCount(3))
88+
89+
gotb, bok := c.Get("b")
90+
fmt.Println(gotb, bok)
91+
92+
// Output:
93+
// 1 true
94+
// 2 true
95+
}
96+
7997
func ExampleCache_Delete() {
8098
c := cache.New(cache.AsMRU[string, int]())
8199
c.Set("a", 1)

policy/clock/clock.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package clock
22

33
import (
44
"container/ring"
5+
6+
"github.com/Code-Hex/go-generics-cache/policy/internal/policyutil"
57
)
68

79
// Cache is used The clock cache replacement policy.
@@ -73,7 +75,7 @@ func (c *Cache[K, V]) Set(key K, val V) {
7375
c.hand.Value = &entry[K, V]{
7476
key: key,
7577
val: val,
76-
referenceCount: 1,
78+
referenceCount: policyutil.GetReferenceCount(val),
7779
}
7880
c.items[key] = c.hand
7981
c.hand = c.hand.Next()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package policyutil
2+
3+
// GetReferenceCount gets reference count from cache value.
4+
func GetReferenceCount(v any) int {
5+
if getter, ok := v.(interface{ GetReferenceCount() int }); ok {
6+
return getter.GetReferenceCount()
7+
}
8+
return 1
9+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package policyutil
2+
3+
import (
4+
"testing"
5+
)
6+
7+
type refCounter struct {
8+
count int
9+
}
10+
11+
func (r refCounter) GetReferenceCount() int {
12+
return r.count
13+
}
14+
15+
func TestGetReferenceCount(t *testing.T) {
16+
tests := []struct {
17+
name string
18+
input any
19+
want int
20+
}{
21+
{
22+
name: "with GetReferenceCount() method",
23+
input: refCounter{count: 5},
24+
want: 5,
25+
},
26+
{
27+
name: "without GetReferenceCount() method",
28+
input: "sample string",
29+
want: 1,
30+
},
31+
}
32+
33+
for _, test := range tests {
34+
t.Run(test.name, func(t *testing.T) {
35+
output := GetReferenceCount(test.input)
36+
if output != test.want {
37+
t.Errorf("want %d, got %d", test.want, output)
38+
}
39+
})
40+
}
41+
}

policy/lfu/priotiry_queue.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package lfu
33
import (
44
"container/heap"
55
"time"
6+
7+
"github.com/Code-Hex/go-generics-cache/policy/internal/policyutil"
68
)
79

810
type entry[K comparable, V any] struct {
@@ -18,7 +20,7 @@ func newEntry[K comparable, V any](key K, val V) *entry[K, V] {
1820
index: 0,
1921
key: key,
2022
val: val,
21-
referenceCount: 1,
23+
referenceCount: policyutil.GetReferenceCount(val),
2224
referencedAt: time.Now(),
2325
}
2426
}

0 commit comments

Comments
 (0)