Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 4 additions & 29 deletions ccache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,26 @@ import (
"sync"
)

type entry[T any] struct {
result T
err error
ready chan struct{}
}

// CCache implements a concurrent cache that memoizes function results.
// It is safe for concurrent use and has no size limit.
// Multiple goroutines can request the same key concurrently,
// but the function will only be executed once.
type CCache[T any] struct {
mu sync.Mutex
m map[string]*entry[T]
m sync.Map
}

// New creates a new concurrent cache.
// The cache has no size limit and will grow as needed.
func New[T any]() *CCache[T] {
c := &CCache[T]{
m: make(map[string]*entry[T]),
}

return c
return &CCache[T]{}
}

// Do executes and memoizes the result of function f with the given key.
// If the key exists in the cache, the cached result is returned.
// If multiple goroutines call Do with the same key concurrently,
// only one execution of f will occur, and all callers will receive the same result.
func (c *CCache[T]) Do(key string, f func() (T, error)) (T, error) {
c.mu.Lock()
e, ok := c.m[key]
if !ok {
e = &entry[T]{
ready: make(chan struct{}),
}
c.m[key] = e
c.mu.Unlock()

e.result, e.err = f()
close(e.ready)
} else {
c.mu.Unlock()
<-e.ready
}
v, _ := c.m.LoadOrStore(key, sync.OnceValues(f))

return e.result, e.err
return v.(func() (T, error))()
}
Loading