-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfuncache.go
More file actions
88 lines (78 loc) · 2.42 KB
/
funcache.go
File metadata and controls
88 lines (78 loc) · 2.42 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
// Package funcache inspired by https://docs.python.org/3/library/functools.html powered LRU cache, LFU cache ARC cache and decorator pattern
package funcache
import (
"reflect"
"github.com/FelixSeptem/collections/arc"
"github.com/FelixSeptem/collections/lfu"
"github.com/FelixSeptem/collections/lru"
)
// wrapped function input and out put both are slice of interface{}
// all elements in it shall be comparable type due to https://golang.org/ref/spec#Comparison_operators generally not pointer,map,slice
type WrappedFun func([]interface{}) ([]interface{}, error)
// cache interface to get and set data use cache
type cache interface {
Set(key, value interface{}) bool
Get(key interface{}) (interface{}, bool)
}
// input an array or a slice convert to a slice
func toSlice(in interface{}) interface{} {
a := reflect.ValueOf(in)
if a.Kind() == reflect.Slice {
return in
}
if a.Kind() != reflect.Array {
panic("shall input a slice or an array")
}
t := reflect.SliceOf(a.Type().Elem())
s := reflect.New(t).Elem()
reflect.Copy(s, a)
return s.Interface()
}
// input a slice or an array convert to an array
func toArray(in interface{}) interface{} {
s := reflect.ValueOf(in)
if s.Kind() == reflect.Array {
return in
}
if s.Kind() != reflect.Slice {
panic("shall input a slice or an array")
}
t := reflect.ArrayOf(s.Len(), s.Type().Elem())
a := reflect.New(t).Elem()
reflect.Copy(a, s)
return a.Interface()
}
// use given cache to cache expensive operate results
func CachedFun(wrapped WrappedFun, retries int, cache cache) WrappedFun {
return func(in []interface{}) ([]interface{}, error) {
key := toArray(in)
if out, ok := cache.Get(key); ok {
result := toSlice(out)
return result.([]interface{}), nil
}
var (
res []interface{}
err error
)
for i := 0; i < retries; i++ {
res, err = wrapped(in)
if err == nil {
cache.Set(key, res)
return res, nil
}
}
return res, err
}
}
// use LRU with CacheFun
func CacheFunWithLru(cacheSize int, wrapped WrappedFun, retries int) WrappedFun {
return CachedFun(wrapped, retries, lru.NewLRUCache(cacheSize))
}
// use LFU with CacheFun
func CacheFunWithLfu(cacheSize int, wrapped WrappedFun, retries int) WrappedFun {
return CachedFun(wrapped, retries, lfu.NewLFUCache(cacheSize))
}
// use ARC with CacheFun
func CacheFunWithArc(cacheSize int, wrapped WrappedFun, retries int) WrappedFun {
return CachedFun(wrapped, retries, arc.NewARCCache(cacheSize))
}