-
Notifications
You must be signed in to change notification settings - Fork 0
/
memoize.go
62 lines (48 loc) · 1.02 KB
/
memoize.go
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
package memoize
import (
"fmt"
"reflect"
)
func Memo[T any](fn T) (m T, cache CacheControl, err error) {
fnt := reflect.TypeOf(fn)
if fnt.Kind() != reflect.Func {
return fn, nil, ErrNotAFunc
}
if fnt.NumIn() == 0 {
return fn, nil, ErrMissingArgs
}
if fnt.NumOut() == 0 {
return fn, nil, ErrMissingReturns
}
fnv := reflect.ValueOf(fn)
cc := &cacheControl{
cacheRoot: map[interface{}]interface{}{},
}
ret := reflect.MakeFunc(fnt, func(args []reflect.Value) (results []reflect.Value) {
defer func() {
r := recover()
if r == nil {
return
}
err, ok := r.(error)
if !ok {
// should always be an error, but just in case...
panic(r)
}
panic(fmt.Errorf("panic in memo stub: %w", err))
}()
cResults := cc.fillAndCheck(args)
if cResults == nil {
if fnt.IsVariadic() {
results = fnv.CallSlice(args)
} else {
results = fnv.Call(args)
}
cc.fillAndSet(args, results)
} else {
results = cResults
}
return results
})
return ret.Interface().(T), cc, nil
}