Skip to content

Commit ac1034e

Browse files
committed
Add adapter for patrickmn/go-cache
1 parent a963118 commit ac1034e

File tree

4 files changed

+121
-2
lines changed

4 files changed

+121
-2
lines changed

README.md

+44-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ type Cacher[K any, V any] interface {
6666
}
6767
```
6868

69-
## Note on Cacher interface
69+
## Cacher interface
7070

7171
* `memoize` require the cache interface to implement two simple `Load` and `Store` functions
7272
* So you can adapt any other caching library to `memoize`
@@ -81,6 +81,49 @@ type Cacher[K any, V any] interface {
8181
* `WithFallback`, `WithReadOnly`, and `WithWriteOnly`...etc wraps a cacher or more to provide or supress functionality
8282
* `cache/adapters` subpackage include adapters for popular Go caches to `Cacher` interface. such as [Hashicorp/LRU](https://github.com/hashicorp/golang-lru)
8383

84+
## Cache adapters
85+
86+
`cache/adapters` include adapters for popular go caches. here are examples for using them with `memoize`
87+
88+
### [Patrickmn/go-cache](https://github.com/patrickmn/go-cache)
89+
90+
```go
91+
import (
92+
"github.com/patrickmn/go-cache"
93+
"github.com/emad-elsaid/memoize"
94+
"github.com/emad-elsaid/memoize/cache/adapters/patrickmn"
95+
)
96+
97+
// strlen function memoized for 5 minutes with expired items cleaned every 10 minutes
98+
var strlen = memoize.NewWithCache(
99+
patrickmn.GoCache[int](
100+
cache.New(5*time.Minute, 10*time.Minute)
101+
),
102+
103+
func(s string) int {
104+
return len(s)
105+
},
106+
)
107+
```
108+
109+
### [Hashicorp/golang-lru/v2](https://github.com/hashicorp/golang-lru)
110+
111+
```go
112+
import (
113+
"https://github.com/hashicorp/golang-lru/v2"
114+
"github.com/emad-elsaid/memoize"
115+
"github.com/emad-elsaid/memoize/cache/adapters/hashicorp"
116+
)
117+
118+
// strlen function memoized with max 1000 stored items
119+
var strlen = memoize.NewWithCache(
120+
hashicorp.LRU(
121+
lru.New[string, int](1000),
122+
),
123+
func(s string) int { return len(s) },
124+
)
125+
```
126+
84127
## Brenchmarks
85128

86129
Each struct is tested with two benchmarks:

cache/adapters/hashicorp/lru.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"github.com/emad-elsaid/memoize/cache"
66
)
77

8-
// Hashicorp LRU cache interface (the part we need)
8+
// Hashicorp LRU cache interface (the part meomize need)
99
type HashicorpLRU[K comparable, V any] interface {
1010
Get(K) (V, bool)
1111
Add(K, V) bool

cache/adapters/patrickmn/go-cache.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Package patrickmn includes cache adapter for https://github.com/patrickmn/go-cache package
2+
package patrickmn
3+
4+
5+
import (
6+
"github.com/emad-elsaid/memoize/cache"
7+
)
8+
9+
// GoCacher cache interface (the part memoize need)
10+
type GoCacher interface {
11+
Get(k string) (any, bool)
12+
SetDefault(k string, x any)
13+
}
14+
15+
// GoCache creates a new cacher from the patrickmn/go-cache
16+
// For example:
17+
//
18+
// c := cache.New(5*time.Minute, 10*time.Minute)
19+
// memoize.NewWithCache(
20+
// patrickmn.GoCache[int](c),
21+
// func(s string) int { return len(s) },
22+
// )
23+
func GoCache[V any](c GoCacher) cache.Cacher[string, V] {
24+
return &goCache[V]{c}
25+
}
26+
27+
type goCache[V any] struct {
28+
GoCacher
29+
}
30+
31+
func (h *goCache[V]) Load(key string) (value V, loaded bool) {
32+
out, loaded := h.GoCacher.Get(key)
33+
val, ok := out.(V)
34+
35+
if !ok {
36+
return value, false
37+
}
38+
39+
return val, true
40+
}
41+
42+
func (h *goCache[V]) Store(key string, value V) {
43+
h.GoCacher.SetDefault(key, value)
44+
}
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package patrickmn
2+
3+
import (
4+
"testing"
5+
)
6+
7+
type Mock map[string]any
8+
9+
10+
func (m Mock) Get(k string) (any, bool) {
11+
v, ok := m[k]
12+
return v, ok
13+
}
14+
15+
func (m Mock) SetDefault(k string, x any) {
16+
m[k] = x
17+
}
18+
19+
func TestGoCache(t *testing.T) {
20+
m := Mock{}
21+
cacher := GoCache[int](m)
22+
cacher.Store("k1", 1)
23+
24+
v, ok := cacher.Load("k1")
25+
if v != 1 {
26+
t.Error("Expected", 1, "got", v)
27+
}
28+
29+
if !ok {
30+
t.Error("Expected", true, "got", ok)
31+
}
32+
}

0 commit comments

Comments
 (0)