diff --git a/cache.go b/cache.go index db88d2f..b5d7f24 100644 --- a/cache.go +++ b/cache.go @@ -81,6 +81,22 @@ func (c *cache) set(k string, x interface{}, d time.Duration) { } } +// Lazily compute the given function and store its result item +// to cache. Returns the computed item and a bool indicating +// whether the item was updated. +func (c *cache) Memoize(k string, f func() interface{}, d time.Duration) (interface{}, bool) { + c.mu.Lock() + v, found := c.get(k) + if found { + c.mu.Unlock() + return v, !found + } + v = f() + c.set(k, v, d) + c.mu.Unlock() + return v, !found +} + // Add an item to the cache, replacing any existing item, using the default // expiration. func (c *cache) SetDefault(k string, x interface{}) { diff --git a/cache_test.go b/cache_test.go index de3e9d6..8b088d8 100644 --- a/cache_test.go +++ b/cache_test.go @@ -154,6 +154,29 @@ func TestStorePointerToStruct(t *testing.T) { } } +func TestMemoizeFunction(t *testing.T) { + f := func() interface{} { + return 5 + } + + tc := New(DefaultExpiration, 0) + x, updated := tc.Memoize("tmemoize", f, DefaultExpiration) + if !updated { + t.Fatal("tmemoize was not updated") + } + if x.(int) != 5 { + t.Fatal("tmemoize is not 5:", x) + } + + y, updated := tc.Memoize("tmemoize", f, DefaultExpiration) + if updated { + t.Fatal("tmemoize was updated") + } + if y.(int) != 5 { + t.Fatal("tmemoize is not 5:", y) + } +} + func TestIncrementWithInt(t *testing.T) { tc := New(DefaultExpiration, 0) tc.Set("tint", 1, DefaultExpiration)