1package memo 2 3import ( 4 "sync" 5 "time" 6) 7 8type ( 9 Memo struct { 10 f Func 11 mu sync.Mutex //guards cache 12 cache *entry 13 14 cacheDur time.Duration 15 lastCache time.Time 16 } 17 18 Func func() (interface{}, error) 19) 20 21type ( 22 entry struct { 23 res result 24 ready chan struct{} // close when res is read 25 } 26 27 result struct { 28 value interface{} 29 err error 30 } 31) 32 33func New(f Func, cd time.Duration) *Memo { 34 return &Memo{ 35 f: f, 36 cacheDur: cd, 37 } 38} 39 40// Invalidate resets the cache to nil if the memo's given cache duration has 41// elapsed, and returns true if the cache was actually invalidated. 42func (memo *Memo) Invalidate() bool { 43 defer memo.mu.Unlock() 44 memo.mu.Lock() 45 46 if memo.cache != nil && time.Now().Sub(memo.lastCache) > memo.cacheDur { 47 memo.cache = nil 48 memo.lastCache = time.Now() 49 return true 50 } 51 return false 52} 53 54func (memo *Memo) Get() (value interface{}, err error) { 55 memo.mu.Lock() 56 if memo.cache == nil { 57 memo.cache = &entry{ready: make(chan struct{})} 58 memo.mu.Unlock() 59 60 memo.cache.res.value, memo.cache.res.err = memo.f() 61 62 close(memo.cache.ready) 63 } else { 64 memo.mu.Unlock() 65 66 <-memo.cache.ready 67 } 68 return memo.cache.res.value, memo.cache.res.err 69} 70 71// Reset forcibly resets the cache to nil without checking if the cache 72// duration has elapsed. 73func (memo *Memo) Reset() { 74 defer memo.mu.Unlock() 75 memo.mu.Lock() 76 77 memo.cache = nil 78 memo.lastCache = time.Now() 79} 80