-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmemoize.go
More file actions
232 lines (214 loc) · 8.82 KB
/
memoize.go
File metadata and controls
232 lines (214 loc) · 8.82 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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
package go_memoize
import (
"time"
)
// Memoize returns a memoized version of the compute function with a specified TTL.
// V is the type of the value returned by the compute function.
func Memoize[V any](computeFn func() V, ttl time.Duration) func() V {
cache := NewCacheSized[uint64, V](1, int64(ttl.Seconds()))
return func() V {
return cache.GetOrCompute(0, func() V {
return computeFn()
})
}
}
// Memoize1 returns a memoized version of the compute function with a single key and a specified TTL.
// K is the type of the key, and V is the type of the value returned by the compute function.
func Memoize1[K comparable, V any](computeFn func(K) V, ttl time.Duration) func(K) V {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(k K) V {
return cache.GetOrCompute(hash1(k), func() V {
return computeFn(k)
})
}
}
// Memoize2 returns a memoized version of the compute function with two keys and a specified TTL.
// K1 and K2 are the types of the keys, and V is the type of the value returned by the compute function.
func Memoize2[K1, K2 comparable, V any](computeFn func(K1, K2) V, ttl time.Duration) func(K1, K2) V {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2) V {
return cache.GetOrCompute(hash2(key1, key2), func() V {
return computeFn(key1, key2)
})
}
}
// Memoize3 returns a memoized version of the compute function with three keys and a specified TTL.
// K1, K2, and K3 are the types of the keys, and V is the type of the value returned by the compute function.
func Memoize3[K1, K2, K3 comparable, V any](computeFn func(K1, K2, K3) V, ttl time.Duration) func(K1, K2, K3) V {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2, key3 K3) V {
return cache.GetOrCompute(hash3(key1, key2, key3), func() V {
return computeFn(key1, key2, key3)
})
}
}
// Memoize4 returns a memoized version of the compute function with four keys and a specified TTL.
// K1, K2, K3, and K4 are the types of the keys, and V is the type of the value returned by the compute function.
func Memoize4[K1, K2, K3, K4 comparable, V any](computeFn func(K1, K2, K3, K4) V, ttl time.Duration) func(K1, K2, K3, K4) V {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2, key3 K3, key4 K4) V {
return cache.GetOrCompute(hash4(key1, key2, key3, key4), func() V {
return computeFn(key1, key2, key3, key4)
})
}
}
// Memoize5 returns a memoized version of the compute function with five keys and a specified TTL.
// K1, K2, K3, K4, and K5 are the types of the keys, and V is the type of the value returned by the compute function.
func Memoize5[K1, K2, K3, K4, K5 comparable, V any](computeFn func(K1, K2, K3, K4, K5) V, ttl time.Duration) func(K1, K2, K3, K4, K5) V {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2, key3 K3, key4 K4, key5 K5) V {
return cache.GetOrCompute(hash5(key1, key2, key3, key4, key5), func() V {
return computeFn(key1, key2, key3, key4, key5)
})
}
}
// Memoize6 returns a memoized version of the compute function with six keys and a specified TTL.
// K1, K2, K3, K4, K5, and K6 are the types of the keys, and V is the type of the value returned by the compute function.
func Memoize6[K1, K2, K3, K4, K5, K6 comparable, V any](computeFn func(K1, K2, K3, K4, K5, K6) V, ttl time.Duration) func(K1, K2, K3, K4, K5, K6) V {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2, key3 K3, key4 K4, key5 K5, key6 K6) V {
return cache.GetOrCompute(hash6(key1, key2, key3, key4, key5, key6), func() V {
return computeFn(key1, key2, key3, key4, key5, key6)
})
}
}
// Memoize7 returns a memoized version of the compute function with seven keys and a specified TTL.
// K1, K2, K3, K4, K5, K6, and K7 are the types of the keys, and V is the type of the value returned by the compute function.
func Memoize7[K1, K2, K3, K4, K5, K6, K7 comparable, V any](computeFn func(K1, K2, K3, K4, K5, K6, K7) V, ttl time.Duration) func(K1, K2, K3, K4, K5, K6, K7) V {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2, key3 K3, key4 K4, key5 K5, key6 K6, key7 K7) V {
return cache.GetOrCompute(hash7(key1, key2, key3, key4, key5, key6, key7), func() V {
return computeFn(key1, key2, key3, key4, key5, key6, key7)
})
}
}
// --- New variants that return an error and avoid caching when computeFn returns a non-nil error ---
// MemoizeE memoizes a function that returns (V, error). Errors are not cached.
func MemoizeE[V any](computeFn func() (V, error), ttl time.Duration) func() (V, error) {
cache := NewCacheSized[uint64, V](1, int64(ttl.Seconds()))
return func() (V, error) {
// try cached
if v, ok := cache.Get(0); ok {
return v, nil
}
// compute
v, err := computeFn()
if err != nil {
return zeroValue[V](), err
}
cache.Set(0, v)
return v, nil
}
}
// Memoize1E memoizes a function with 1 arg that returns (V, error). Errors are not cached.
func Memoize1E[K comparable, V any](computeFn func(K) (V, error), ttl time.Duration) func(K) (V, error) {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(k K) (V, error) {
key := hash1(k)
if v, ok := cache.Get(key); ok {
return v, nil
}
v, err := computeFn(k)
if err != nil {
return zeroValue[V](), err
}
cache.Set(key, v)
return v, nil
}
}
// Memoize2E memoizes a function with 2 args that returns (V, error). Errors are not cached.
func Memoize2E[K1, K2 comparable, V any](computeFn func(K1, K2) (V, error), ttl time.Duration) func(K1, K2) (V, error) {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2) (V, error) {
key := hash2(key1, key2)
if v, ok := cache.Get(key); ok {
return v, nil
}
v, err := computeFn(key1, key2)
if err != nil {
return zeroValue[V](), err
}
cache.Set(key, v)
return v, nil
}
}
// Memoize3E memoizes a function with 3 args that returns (V, error). Errors are not cached.
func Memoize3E[K1, K2, K3 comparable, V any](computeFn func(K1, K2, K3) (V, error), ttl time.Duration) func(K1, K2, K3) (V, error) {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2, key3 K3) (V, error) {
key := hash3(key1, key2, key3)
if v, ok := cache.Get(key); ok {
return v, nil
}
v, err := computeFn(key1, key2, key3)
if err != nil {
return zeroValue[V](), err
}
cache.Set(key, v)
return v, nil
}
}
// Memoize4E memoizes a function with 4 args that returns (V, error). Errors are not cached.
func Memoize4E[K1, K2, K3, K4 comparable, V any](computeFn func(K1, K2, K3, K4) (V, error), ttl time.Duration) func(K1, K2, K3, K4) (V, error) {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2, key3 K3, key4 K4) (V, error) {
key := hash4(key1, key2, key3, key4)
if v, ok := cache.Get(key); ok {
return v, nil
}
v, err := computeFn(key1, key2, key3, key4)
if err != nil {
return zeroValue[V](), err
}
cache.Set(key, v)
return v, nil
}
}
// Memoize5E memoizes a function with 5 args that returns (V, error). Errors are not cached.
func Memoize5E[K1, K2, K3, K4, K5 comparable, V any](computeFn func(K1, K2, K3, K4, K5) (V, error), ttl time.Duration) func(K1, K2, K3, K4, K5) (V, error) {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2, key3 K3, key4 K4, key5 K5) (V, error) {
key := hash5(key1, key2, key3, key4, key5)
if v, ok := cache.Get(key); ok {
return v, nil
}
v, err := computeFn(key1, key2, key3, key4, key5)
if err != nil {
return zeroValue[V](), err
}
cache.Set(key, v)
return v, nil
}
}
// Memoize6E memoizes a function with 6 args that returns (V, error). Errors are not cached.
func Memoize6E[K1, K2, K3, K4, K5, K6 comparable, V any](computeFn func(K1, K2, K3, K4, K5, K6) (V, error), ttl time.Duration) func(K1, K2, K3, K4, K5, K6) (V, error) {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2, key3 K3, key4 K4, key5 K5, key6 K6) (V, error) {
key := hash6(key1, key2, key3, key4, key5, key6)
if v, ok := cache.Get(key); ok {
return v, nil
}
v, err := computeFn(key1, key2, key3, key4, key5, key6)
if err != nil {
return zeroValue[V](), err
}
cache.Set(key, v)
return v, nil
}
}
// Memoize7E memoizes a function with 7 args that returns (V, error). Errors are not cached.
func Memoize7E[K1, K2, K3, K4, K5, K6, K7 comparable, V any](computeFn func(K1, K2, K3, K4, K5, K6, K7) (V, error), ttl time.Duration) func(K1, K2, K3, K4, K5, K6, K7) (V, error) {
cache := NewCache[uint64, V](int64(ttl.Seconds()))
return func(key1 K1, key2 K2, key3 K3, key4 K4, key5 K5, key6 K6, key7 K7) (V, error) {
key := hash7(key1, key2, key3, key4, key5, key6, key7)
if v, ok := cache.Get(key); ok {
return v, nil
}
v, err := computeFn(key1, key2, key3, key4, key5, key6, key7)
if err != nil {
return zeroValue[V](), err
}
cache.Set(key, v)
return v, nil
}
}