-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmemoizer.go
More file actions
56 lines (48 loc) · 1.31 KB
/
memoizer.go
File metadata and controls
56 lines (48 loc) · 1.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package memoizer
import (
"fmt"
"strings"
"sync"
"golang.org/x/sync/singleflight"
)
// Memoizer is a thread-safe memoizer that caches the results of a function call.
// It is designed to be used in a ephemeral context, such as a http request.
// That's why there's no expiration mechanism on the cache.
type Memoizer struct {
cache map[string]memoizedResult
mutex sync.RWMutex
singleflight singleflight.Group
}
// NewMemoizer creates a new memoizer instance.
func NewMemoizer() *Memoizer {
return &Memoizer{
cache: map[string]memoizedResult{},
singleflight: singleflight.Group{},
}
}
// Memoize memoizes the result of a function call.
func (m *Memoizer) Memoize(function func() (interface{}, error), keys ...interface{}) (interface{}, error) {
keySlc := []string{}
for _, v := range keys {
keySlc = append(keySlc, fmt.Sprintf("%v", v))
}
key := strings.Join(keySlc, "|")
m.mutex.RLock()
if res, ok := m.cache[key]; ok {
m.mutex.RUnlock()
return res.value, res.err
}
m.mutex.RUnlock()
value, err, _ := m.singleflight.Do(key, func() (interface{}, error) {
value, err := function()
m.mutex.Lock()
m.cache[key] = memoizedResult{value: value, err: err}
m.mutex.Unlock()
return value, err
})
return value, err
}
type memoizedResult struct {
value interface{}
err error
}